package cn.ug.pay.service.impl;

import cn.ug.account.bean.DataDictionaryBean;
import cn.ug.activity.bean.CouponMemberBean;
import cn.ug.activity.mq.ContractMQ;
import cn.ug.activity.mq.DonationCashMQ;
import cn.ug.activity.mq.RewardsMQ;
import cn.ug.aop.RemoveCache;
import cn.ug.aop.SaveCache;
import cn.ug.bean.base.DataTable;
import cn.ug.bean.base.SerializeObject;
import cn.ug.bean.status.DeleteStatus;
import cn.ug.bean.type.ResultType;
import cn.ug.config.FundRateConfig;
import cn.ug.config.RedisGlobalLock;
import cn.ug.core.ensure.Ensure;
import cn.ug.enums.PayTypeEnum;
import cn.ug.enums.ProductTypeEnum;
import cn.ug.enums.RateKeyEnum;
import cn.ug.enums.WxTemplateEnum;
import cn.ug.feign.*;
import cn.ug.member.bean.MemberDetailBean;
import cn.ug.mq.DelayMessagePostProcessor;
import cn.ug.msg.bean.status.CommonConstants;
import cn.ug.msg.bean.type.SmsType;
import cn.ug.msg.mq.Msg;
import cn.ug.msg.mq.Sms;
import cn.ug.msg.mq.WxMessageParamBean;
import cn.ug.msg.mq.WxNotifyData;
import cn.ug.pay.bean.*;
import cn.ug.pay.bean.response.MemberAccountBean;
import cn.ug.pay.bean.type.BillGoldTradeType;
import cn.ug.pay.bean.type.PayType;
import cn.ug.pay.bean.type.ProductOrderPayStatus;
import cn.ug.pay.bean.type.ProductOrderStatus;
import cn.ug.pay.mapper.*;
import cn.ug.pay.mapper.entity.PayExperienceOrder;
import cn.ug.pay.mapper.entity.ProductOrder;
import cn.ug.pay.mapper.entity.ProductOrderFee;
import cn.ug.pay.service.MemberAccountService;
import cn.ug.pay.service.MemberGoldService;
import cn.ug.pay.service.ProductOrderService;
import cn.ug.product.bean.GoldLatestPriceBean;
import cn.ug.product.bean.response.ProductFindBean;
import cn.ug.service.impl.BaseServiceImpl;
import cn.ug.util.BigDecimalUtil;
import cn.ug.util.DateUtils;
import cn.ug.util.SerialNumberWorker;
import cn.ug.util.UF;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerBeanMapper;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

import static cn.ug.config.CacheType.OBJECT;
import static cn.ug.config.CacheType.SEARCH;
import static cn.ug.config.QueueName.*;
import static cn.ug.pay.bean.type.ProductOrderPayStatus.COMPLETE;
import static cn.ug.pay.bean.type.ProductOrderPayStatus.WAIT;
import static cn.ug.pay.bean.type.ProductOrderStatus.EXPIRED;
import static cn.ug.pay.bean.type.ProductOrderStatus.NOT_EXPIRED;
import static cn.ug.util.ConstantUtil.*;
import static java.math.BigDecimal.ROUND_HALF_UP;

/**
 * @author kaiwotech
 */
@Service
public class ProductOrderServiceImpl extends BaseServiceImpl implements ProductOrderService {
    private static final String ONLINE_DATE = "2018-05-01";
    @Resource
    private ProductOrderMapper productOrderMapper;
    @Resource
    private ProductOrderFeeMapper productOrderFeeMapper;
    @Resource
    private ProductService productService;
    @Resource
    private MemberGoldService memberGoldService;
    @Autowired
    private GoldRecordMapper goldRecordMapper;
    @Resource
    private PriceService priceService;
    @Resource
    private MemberAccountService memberAccountService;
    @Resource
    private CouponRepertoryService couponRepertoryService;
    @Resource
    private RedisGlobalLock redisGlobalLock;
    @Resource
    private FundRateConfig fundRateConfig;
    @Resource
    private DozerBeanMapper dozerBeanMapper;
    @Resource
    private AmqpTemplate amqpTemplate;
    @Autowired
    private DataDictionaryService dataDictionaryService;
    @Autowired
    private RateSettingsService rateSettingsService;

    @Autowired
    private PayTbillMapper payTbillMapper;

    @Autowired
    private PayExperienceOrderMapper payExperienceOrderMapper;

    //每日最高可购克重
    private static final String BUY_MAX_GRAM_PERDAY = "buyMaxGramPerDay";

    @Override
    public int countActivityOrders(String memberId, String productId) {
        if (StringUtils.isNotBlank(memberId) && StringUtils.isNotBlank(productId)) {
            return productOrderMapper.countActivityOrders(memberId, productId);
        }
        return 0;
    }

    @Override
    public MemberDetailBean getMemberTradeInfo(String memberId) {
        if (StringUtils.isNotBlank(memberId)) {
            MemberDetailBean bean = productOrderMapper.selectMemberTradeInfo(memberId);
            if (bean != null) {
                int num = productOrderMapper.countTradeNum(memberId);
                if (num == 1) {
                    bean.setInvestmentStatus(3);
                } else if (num > 1) {
                    bean.setInvestmentStatus(4);
                }
                MemberDetailBean detailBean = payTbillMapper.selectMemberTradeInfo(memberId);
                if (detailBean != null) {
                    if (StringUtils.isBlank(bean.getFirstInvestmentTime()) && StringUtils.isNotBlank(detailBean.getFirstInvestmentTime())) {
                        bean.setFirstInvestmentTime(detailBean.getFirstInvestmentTime());
                    }
                    if (bean.getFirstInvestmentAmount() == null || bean.getFirstInvestmentAmount().doubleValue() == 0) {
                        if (detailBean.getFirstInvestmentAmount() != null) {
                            bean.setFirstInvestmentAmount(detailBean.getFirstInvestmentAmount());
                        }
                    }
                    if (StringUtils.isBlank(bean.getSecondInvestmentTime()) && StringUtils.isNotBlank(detailBean.getSecondInvestmentTime())) {
                        bean.setSecondInvestmentTime(detailBean.getSecondInvestmentTime());
                    }
                    bean.setReInvestNum(bean.getReInvestNum() + detailBean.getReInvestNum());
                    if (bean.getBuyGram() == null) {
                        bean.setBuyGram(BigDecimal.ZERO);
                    }
                    if (detailBean.getBuyGram() != null) {
                        bean.setBuyGram(bean.getBuyGram().add(detailBean.getBuyGram()));
                    }
                }
            }
            return bean;
        }
        return null;
    }

    @Override
    public int queryRFMLabelCount() {
        return productOrderMapper.queryRFMLabelCount();
    }

    @Override
    public List<EverydayBuyGoldBean> queryEverydayBuyGoldRecords(String payDate) {
        if (StringUtils.isNotBlank(payDate)) {
            int date = Integer.parseInt(StringUtils.replaceAll(payDate, "-", ""));
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            int currentDate = Integer.parseInt(format.format(Calendar.getInstance().getTime()));
            if (date >= currentDate) {
                return null;
            }
            List<EverydayBuyGoldBean> result = productOrderMapper.queryEverydayBuyGoldRecords(payDate);
            if (result == null || result.size() == 0) {
                EverydayBuyGoldBean bean = new EverydayBuyGoldBean();
                bean.setPayDate(payDate);
                bean.setPayAmount(BigDecimal.ZERO);
                bean.setPayGram(BigDecimal.ZERO);
                result.add(bean);
            }
            return result;
        } else {
            List<EverydayBuyGoldBean> result = new ArrayList<EverydayBuyGoldBean>();
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_YEAR, -1);
            for (; ; ) {
                EverydayBuyGoldBean bean = new EverydayBuyGoldBean();
                bean.setPayDate(dateFormat.format(calendar.getTime()));
                result.add(bean);
                if (StringUtils.equals("2018-04-27", dateFormat.format(calendar.getTime()))) {
                    break;
                }
                calendar.add(Calendar.DAY_OF_YEAR, -1);
            }
            List<EverydayBuyGoldBean> records = productOrderMapper.queryEverydayBuyGoldRecords(payDate);
            for (EverydayBuyGoldBean bean : result) {
                if (records != null && records.size() > 0) {
                    for (EverydayBuyGoldBean record : records) {
                        if (StringUtils.equals(bean.getPayDate(), record.getPayDate())) {
                            bean.setPayAmount(record.getPayAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
                            bean.setPayGram(record.getPayGram().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (EverydayBuyGoldBean bean : result) {
                if (bean.getPayGram() == null) {
                    bean.setPayGram(BigDecimal.ZERO);
                }
                if (bean.getPayAmount() == null) {
                    bean.setPayAmount(BigDecimal.ZERO);
                }
            }
            return result;
        }
    }

    @Override
    public List<BuyGoldRecordBean> queryBuyGoldRecord(String payDate, int offset, int size) {
        if (StringUtils.isNotBlank(payDate)) {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("payDate", payDate);
            params.put("offset", offset);
            params.put("size", size);
            return productOrderMapper.queryBuyGoldRecord(params);
        }
        return null;
    }

    @Override
    public int countBuyGoldRecord(String payDate) {
        if (StringUtils.isNotBlank(payDate)) {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("payDate", payDate);
            return productOrderMapper.countBuyGoldRecord(params);
        }

        return 0;
    }


    @Override
    public int findRegularBuyCount(String memberId) {
        return productOrderMapper.findRegularBuyCount(memberId);
    }

    @Override
    public int findRegularActivityBuyCount(String memberId) {
        return productOrderMapper.findRegularActivityBuyCount(memberId);
    }


    @Override
    public List<RFMLabelBean> queryRFMLabelList(String startDate, String endDate, int offset, int size) {
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("startDate", startDate);
            params.put("endDate", endDate);
            params.put("offset", offset);
            params.put("size", size);
            return productOrderMapper.queryRFMLabelList(params);
        }
        return null;
    }

    @Override
    public List<KValueBean> listKValue(String searchDate) {
        List<KValueBean> result = new ArrayList<KValueBean>();
        if (StringUtils.isNotBlank(searchDate)) {
            double defaultValue = 270;
            String startDate = "";
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(searchDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                for (; ; ) {
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        KValueBean bean = new KValueBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                    }
                    if (StringUtils.equals(dateFormat.format(calendar.getTime()), ONLINE_DATE)) {
                        startDate = dateFormat.format(calendar.getTime());
                        break;
                    }
                    if (result.size() > 66) {
                        startDate = dateFormat.format(calendar.getTime());
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String avgStartDate = getStartDate(startDate);
            List<GoldLatestPriceBean> temp = new ArrayList<GoldLatestPriceBean>();
            try {
                Date time = dateFormat.parse(searchDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(time);
                for (; ; ) {
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        GoldLatestPriceBean bean = new GoldLatestPriceBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        temp.add(bean);
                    }
                    if (StringUtils.equals(dateFormat.format(calendar.getTime()), avgStartDate)) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            SerializeObject<List<GoldLatestPriceBean>> priceBeans = priceService.listLatestPrice(avgStartDate, searchDate);
            if (priceBeans != null && priceBeans.getData() != null) {
                List<GoldLatestPriceBean> priceData = priceBeans.getData();
                for (GoldLatestPriceBean priceBean : temp) {
                    for (GoldLatestPriceBean value : priceData) {
                        if (StringUtils.equals(priceBean.getTime(), value.getTime())) {
                            priceBean.setOpeningPrice(value.getOpeningPrice());
                            priceBean.setClosingPrice(value.getClosingPrice());
                            if (value.getLatestpri() != null) {
                                priceBean.setLatestpri(value.getLatestpri().setScale(2, BigDecimal.ROUND_HALF_UP));
                            } else {
                                priceBean.setLatestpri(new BigDecimal(defaultValue));
                            }
                            if (value.getMaxPrice() != null) {
                                priceBean.setMaxPrice(value.getMaxPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
                            } else {
                                priceBean.setMaxPrice(new BigDecimal(defaultValue));
                            }
                            if (value.getMinPrice() != null) {
                                priceBean.setMinPrice(value.getMinPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
                            } else {
                                priceBean.setMinPrice(new BigDecimal(defaultValue));
                            }
                            break;
                        }
                    }
                }
            } else {
                return null;
            }

            //List<KValueBean> maxValue = productOrderMapper.listMaxValue(startDate, searchDate);
            //List<KValueBean> minValue = productOrderMapper.listMinValue(startDate, searchDate);
            List<KValueBean> avgValue = productOrderMapper.listAvgValue(avgStartDate, searchDate);
            for (GoldLatestPriceBean priceBean : temp) {
                if (avgValue != null && avgValue.size() > 0) {
                    for (KValueBean avgValueBean : avgValue) {
                        if (StringUtils.equals(priceBean.getTime(), avgValueBean.getTime()) && avgValueBean.getMa1() != null) {
                            priceBean.setLatestpri(avgValueBean.getMa1().setScale(2, BigDecimal.ROUND_HALF_UP));
                        }

                        if (StringUtils.equals(priceBean.getTime(), avgValueBean.getTime()) && avgValueBean.getMa1() != null) {
                            priceBean.setLatestpri(avgValueBean.getMa1().setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (GoldLatestPriceBean priceBean : temp) {
                if (priceBean.getLatestpri() == null) {
                    priceBean.setLatestpri(new BigDecimal(defaultValue));
                }
            }

            for (KValueBean bean : result) {
                List<String> oneDayTime = new ArrayList<String>();
                List<String> fiveDayTime = new ArrayList<String>();
                List<String> twentyTwoDayDayTime = new ArrayList<String>();
                try {
                    Date time = dateFormat.parse(bean.getTime());
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(time);
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                    for (; ; ) {
                        int week = calendar.get(Calendar.DAY_OF_WEEK);
                        if (week != 1 && week != 7) {
                            if (oneDayTime.size() < 1) {
                                oneDayTime.add(dateFormat.format(calendar.getTime()));
                            }
                            if (fiveDayTime.size() < 5) {
                                fiveDayTime.add(dateFormat.format(calendar.getTime()));
                            }
                            if (twentyTwoDayDayTime.size() < 22) {
                                twentyTwoDayDayTime.add(dateFormat.format(calendar.getTime()));
                            } else {
                                break;
                            }
                            if (StringUtils.equals(dateFormat.format(calendar.getTime()), avgStartDate)) {
                                break;
                            }
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                double oneDayAmount = 0;
                double fiveDayAmount = 0;
                double twentyTwoDayAmount = 0;
                for (GoldLatestPriceBean priceBean : temp) {
                    if (StringUtils.equals(bean.getTime(), priceBean.getTime())) {
                        bean.setOpeningPrice(priceBean.getOpeningPrice());
                        bean.setClosingPrice(priceBean.getClosingPrice());
                        if (priceBean.getMaxPrice() != null) {
                            bean.setMaxAmount(priceBean.getMaxPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
                        } else {
                            bean.setMaxAmount(priceBean.getLatestpri().setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                    if (StringUtils.equals(bean.getTime(), priceBean.getTime())) {
                        if (priceBean.getMinPrice() != null) {
                            bean.setMinAmount(priceBean.getMinPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
                        } else {
                            bean.setMinAmount(priceBean.getLatestpri().setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                    if (oneDayTime.contains(priceBean.getTime())) {
                        oneDayAmount += priceBean.getLatestpri().doubleValue();
                    }
                    if (fiveDayTime.contains(priceBean.getTime())) {
                        fiveDayAmount += priceBean.getLatestpri().doubleValue();
                    }
                    if (twentyTwoDayDayTime.contains(priceBean.getTime())) {
                        twentyTwoDayAmount += priceBean.getLatestpri().doubleValue();
                    }
                }
                bean.setMa1(new BigDecimal(oneDayAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
                bean.setMa5(new BigDecimal(fiveDayAmount / 5).setScale(2, BigDecimal.ROUND_HALF_UP));
                bean.setMa22(new BigDecimal(twentyTwoDayAmount / 22).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
        }
        return result;
    }

    @Override
    public List<OpenPositionPastBean> listOpenPositionAvgStatistics(String startDate, String endDate) {
        List<OpenPositionPastBean> result = new ArrayList<OpenPositionPastBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(endDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                for (; ; ) {
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        OpenPositionPastBean bean = new OpenPositionPastBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                    }
                    if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String actualStartDate = getStartDate(endDate);
            List<OpenPositionPastBean> beans = productOrderMapper.listOpenPositionAvgStatistics(actualStartDate, endDate);
            for (OpenPositionPastBean bean : result) {
                List<String> oneDayTime = new ArrayList<String>();
                List<String> fiveDayTime = new ArrayList<String>();
                List<String> twentyTwoDayDayTime = new ArrayList<String>();
                try {
                    Date time = dateFormat.parse(bean.getTime());
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(time);
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                    for (; ; ) {
                        int week = calendar.get(Calendar.DAY_OF_WEEK);
                        if (week != 1 && week != 7) {
                            if (oneDayTime.size() < 1) {
                                oneDayTime.add(dateFormat.format(calendar.getTime()));
                            }
                            if (fiveDayTime.size() < 5) {
                                fiveDayTime.add(dateFormat.format(calendar.getTime()));
                            }
                            if (twentyTwoDayDayTime.size() < 22) {
                                twentyTwoDayDayTime.add(dateFormat.format(calendar.getTime()));
                            } else {
                                break;
                            }
                            if (StringUtils.equals(dateFormat.format(calendar.getTime()), actualStartDate)) {
                                break;
                            }
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                double oneDayMoney = 0;
                double fiveDayMoney = 0;
                double twentyTwoDayMoney = 0;
                double oneDayAmount = 0;
                double fiveDayAmount = 0;
                double twentyTwoDayAmount = 0;
                for (OpenPositionPastBean pastBean : beans) {
                    if (oneDayTime.contains(pastBean.getTime())) {
                        oneDayMoney += pastBean.getMa1().doubleValue();
                        oneDayAmount += pastBean.getMa5().doubleValue();
                    }
                    if (fiveDayTime.contains(pastBean.getTime())) {
                        fiveDayMoney += pastBean.getMa1().doubleValue();
                        fiveDayAmount += pastBean.getMa5().doubleValue();
                    }
                    if (twentyTwoDayDayTime.contains(pastBean.getTime())) {
                        twentyTwoDayMoney += pastBean.getMa1().doubleValue();
                        twentyTwoDayAmount += pastBean.getMa5().doubleValue();
                    }
                }
                if (oneDayAmount > 0) {
                    bean.setMa1(new BigDecimal(oneDayMoney / oneDayAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
                if (fiveDayAmount > 0) {
                    bean.setMa5(new BigDecimal(fiveDayMoney / fiveDayAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
                if (twentyTwoDayAmount > 0) {
                    bean.setMa22(new BigDecimal(twentyTwoDayMoney / twentyTwoDayAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
                }
            }
        }
        BigDecimal totalMa1 = BigDecimal.ZERO;
        BigDecimal totalMa5 = BigDecimal.ZERO;
        BigDecimal totalMa22 = BigDecimal.ZERO;
        for (OpenPositionPastBean bean : result) {
            if (bean.getMa1() != null) {
                totalMa1 = totalMa1.add(bean.getMa1());
            }
            if (bean.getMa5() != null) {
                totalMa5 = totalMa5.add(bean.getMa5());
            }
            if (bean.getMa22() != null) {
                totalMa22 = totalMa22.add(bean.getMa22());
            }
        }
        for (OpenPositionPastBean bean : result) {
            if (bean.getMa1() == null) {
                bean.setMa1(BigDecimal.ZERO);
            }
            if (bean.getMa5() == null) {
                bean.setMa5(BigDecimal.ZERO);
            }
            if (bean.getMa22() == null) {
                bean.setMa22(BigDecimal.ZERO);
            }
            bean.setTotalMa1(totalMa1);
            bean.setTotalMa5(totalMa5);
            bean.setTotalMa22(totalMa22);
        }
        return result;
    }

    public String getStartDate(String searchDate) {
        if (StringUtils.isNotBlank(searchDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(searchDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                int index = 0;
                for (; ; ) {
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        index++;
                    }
                    if (index > 22) {
                        return dateFormat.format(calendar.getTime());
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public List<OpenPositionTotalBean> listOpenPositionTotalStatistics(String startDate, String endDate) {
        List<OpenPositionTotalBean> result = new ArrayList<OpenPositionTotalBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(endDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                for (; ; ) {
                    OpenPositionTotalBean bean = new OpenPositionTotalBean();
                    bean.setTime(dateFormat.format(calendar.getTime()));
                    result.add(bean);
                    if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            List<OpenPositionTotalBean> totalResult = productOrderMapper.listOpenPositionTotalStatistics(startDate, endDate);
            BigDecimal totalValue = BigDecimal.ZERO;
            for (OpenPositionTotalBean bean : totalResult) {
                if (bean.getValue() != null) {
                    totalValue = totalValue.add(bean.getValue());
                }
            }
            for (OpenPositionTotalBean bean : result) {
                bean.setTotalValue(totalValue.setScale(2, BigDecimal.ROUND_HALF_UP));
                if (totalResult != null && totalResult.size() > 0) {
                    for (OpenPositionTotalBean averageValueBean : totalResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime())) {
                            bean.setValue(averageValueBean.getValue().setScale(2, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (OpenPositionTotalBean bean : result) {
                if (bean.getValue() == null) {
                    bean.setValue(BigDecimal.ZERO);
                }
                if (bean.getTotalValue() == null) {
                    bean.setTotalValue(BigDecimal.ZERO);
                }
            }
        }
        return result;
    }

    @Override
    public List<OpenPositionTotalBean> listExpiredStatistics(String startDate, String endDate) {
        List<OpenPositionTotalBean> result = new ArrayList<OpenPositionTotalBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(endDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                for (; ; ) {
                    OpenPositionTotalBean bean = new OpenPositionTotalBean();
                    bean.setTime(dateFormat.format(calendar.getTime()));
                    result.add(bean);
                    if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            List<OpenPositionTotalBean> totalResult = productOrderMapper.listExpiredStatistics(startDate, endDate);
            BigDecimal totalValue = BigDecimal.ZERO;
            for (OpenPositionTotalBean bean : totalResult) {
                if (bean.getValue() != null) {
                    totalValue = totalValue.add(bean.getValue());
                }
            }
            for (OpenPositionTotalBean bean : result) {
                bean.setTotalValue(totalValue.setScale(5, BigDecimal.ROUND_HALF_UP));
                if (totalResult != null && totalResult.size() > 0) {
                    for (OpenPositionTotalBean averageValueBean : totalResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime())) {
                            bean.setValue(averageValueBean.getValue().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (OpenPositionTotalBean bean : result) {
                if (bean.getValue() == null) {
                    bean.setValue(BigDecimal.ZERO);
                }
                if (bean.getTotalValue() == null) {
                    bean.setTotalValue(BigDecimal.ZERO);
                }
            }
        }
        return result;
    }

    @Override
    public List<OpenPositionTotalBean> listTransactionWeightStatistics(int payType, String startDate, String endDate) {
        List<OpenPositionTotalBean> result = new ArrayList<OpenPositionTotalBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            try {
                Date endDatetime = dateFormat.parse(endDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                for (; ; ) {
                    OpenPositionTotalBean bean = new OpenPositionTotalBean();
                    bean.setTime(dateFormat.format(calendar.getTime()));
                    result.add(bean);
                    if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            List<OpenPositionTotalBean> totalResult = productOrderMapper.listTransactionWeightStatistics(payType, startDate, endDate);
            BigDecimal totalValue = BigDecimal.ZERO;
            for (OpenPositionTotalBean bean : totalResult) {
                if (bean.getValue() != null) {
                    totalValue = totalValue.add(bean.getValue());
                }
            }
            for (OpenPositionTotalBean bean : result) {
                bean.setTotalValue(totalValue.setScale(5, BigDecimal.ROUND_HALF_UP));
                if (totalResult != null && totalResult.size() > 0) {
                    for (OpenPositionTotalBean averageValueBean : totalResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime())) {
                            bean.setValue(averageValueBean.getValue().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (OpenPositionTotalBean bean : result) {
                if (bean.getValue() == null) {
                    bean.setValue(BigDecimal.ZERO);
                }
                if (bean.getTotalValue() == null) {
                    bean.setTotalValue(BigDecimal.ZERO);
                }
            }
        }
        return result;
    }

    @Override
    public List<TradeFutureValueBean> listTradeFutureValueStatistics(String startDate, String endDate, List<String> channelIds) {
        List<TradeFutureValueBean> result = new ArrayList<TradeFutureValueBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            Calendar futureCalendar = Calendar.getInstance();
            try {
                Date endDatetime = dateFormat.parse(endDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDatetime);
                futureCalendar.setTime(dateFormat.parse(endDate));
                futureCalendar.add(Calendar.DAY_OF_YEAR, 30);
                for (; ; ) {
                    TradeFutureValueBean bean = new TradeFutureValueBean();
                    bean.setTime(dateFormat.format(calendar.getTime()));
                    result.add(bean);
                    if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                        break;
                    }
                    calendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String futureEndDate = dateFormat.format(futureCalendar.getTime());
            List<TradeFutureValueBean> futureResult = productOrderMapper.listTradeFutureValueStatistics(startDate, futureEndDate, channelIds);

            for (TradeFutureValueBean bean : result) {
                if (futureResult != null && futureResult.size() > 0) {
                    double oneDayAmount = 0;
                    double sevenDayAmount = 0;
                    double thirtyDayAmount = 0;
                    List<String> futureSevenTime = new ArrayList<String>();
                    List<String> futureThirtyTime = new ArrayList<String>();
                    try {
                        Date time = dateFormat.parse(bean.getTime());
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(time);
                        int index = 0;
                        for (; ; ) {
                            if (index < 7) {
                                futureSevenTime.add(dateFormat.format(calendar.getTime()));
                            }
                            if (index < 30) {
                                futureThirtyTime.add(dateFormat.format(calendar.getTime()));
                            } else {
                                break;
                            }
                            calendar.add(Calendar.DAY_OF_YEAR, 1);
                            index++;
                        }
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    for (TradeFutureValueBean futureBean : futureResult) {
                        if (futureBean.getOneDayAmount() == null) {
                            continue;
                        }
                        if (StringUtils.equals(futureBean.getTime(), bean.getTime())) {
                            oneDayAmount = futureBean.getOneDayAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                        }
                        if (futureSevenTime.contains(futureBean.getTime())) {
                            sevenDayAmount += futureBean.getOneDayAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                        }
                        if (futureThirtyTime.contains(futureBean.getTime())) {
                            thirtyDayAmount += futureBean.getOneDayAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                        }
                    }
                    bean.setOneDayAmount(new BigDecimal(oneDayAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                    bean.setSevenDayAmount(new BigDecimal(sevenDayAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                    bean.setThirtyDayAmount(new BigDecimal(thirtyDayAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                }
            }
            for (TradeFutureValueBean bean : result) {
                if (bean.getOneDayAmount() == null) {
                    bean.setOneDayAmount(BigDecimal.ZERO);
                }
                if (bean.getSevenDayAmount() == null) {
                    bean.setSevenDayAmount(BigDecimal.ZERO);
                }
                if (bean.getThirtyDayAmount() == null) {
                    bean.setThirtyDayAmount(BigDecimal.ZERO);
                }
            }
        }
        return result;
    }

    @Override
    public List<TradeAverageValueBean> listAvgValueStatistics(int timeType, String startDate, String endDate, List<String> channelIds) {
        List<TradeAverageValueBean> result = new ArrayList<TradeAverageValueBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            if (timeType == 1) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    for (; ; ) {
                        TradeAverageValueBean bean = new TradeAverageValueBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                        if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 2) {
                SimpleDateFormat monthFormat = new SimpleDateFormat(NORMAL_MONTH_FORMAT);
                try {
                    Date endDatetime = monthFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    Set<String> info = new HashSet<String>();
                    for (; ; ) {
                        TradeAverageValueBean bean = new TradeAverageValueBean();
                        String value = monthFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(monthFormat.format(calendar.getTime()));
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, monthFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.MONTH, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 3) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week == 1) {
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                    Set<String> info = new HashSet<String>();
                    SimpleDateFormat weekFormat = new SimpleDateFormat("yyyy-ww");
                    for (; ; ) {
                        TradeAverageValueBean bean = new TradeAverageValueBean();
                        String value = weekFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(value);
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            List<TradeAverageValueBean> avgResult = productOrderMapper.listTradeAvgValueStatistics(timeType, startDate, endDate, channelIds);
            for (TradeAverageValueBean bean : result) {
                if (avgResult != null && avgResult.size() > 0) {
                    for (TradeAverageValueBean averageValueBean : avgResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime()) && averageValueBean.getSingleAmount() != null) {
                            bean.setSingleAmount(averageValueBean.getSingleAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime()) && averageValueBean.getEveryoneAmount() != null) {
                            bean.setEveryoneAmount(averageValueBean.getEveryoneAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (TradeAverageValueBean bean : result) {
                if (bean.getEveryoneAmount() == null) {
                    bean.setEveryoneAmount(BigDecimal.ZERO);
                }
                if (bean.getSingleAmount() == null) {
                    bean.setSingleAmount(BigDecimal.ZERO);
                }
            }
            if (timeType == 3) {
                for (TradeAverageValueBean bean : result) {
                    String[] arrs = StringUtils.split(bean.getTime(), MINUS);
                    bean.setTime(UF.getWeekInterval(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1])));
                }
                result.get(0).setTime(StringUtils.split(result.get(0).getTime(), WAVE)[0] + WAVE + endDate);
                result.get(result.size() - 1).setTime(startDate + WAVE + StringUtils.split(result.get(result.size() - 1).getTime(), WAVE)[1]);
            }
        }
        return result;
    }

    @Override
    public List<OpenPositionTotalBean> listExpiredAmountStatistics(int timeType, String startDate, String endDate, int searchType) {
        List<OpenPositionTotalBean> result = new ArrayList<OpenPositionTotalBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            if (timeType == 1) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                        if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 2) {
                SimpleDateFormat monthFormat = new SimpleDateFormat(NORMAL_MONTH_FORMAT);
                try {
                    Date endDatetime = monthFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    Set<String> info = new HashSet<String>();
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        String value = monthFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(monthFormat.format(calendar.getTime()));
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, monthFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.MONTH, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 3) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week == 1) {
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                    Set<String> info = new HashSet<String>();
                    SimpleDateFormat weekFormat = new SimpleDateFormat("yyyy-ww");
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        String value = weekFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(value);
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            List<OpenPositionTotalBean> expiredResult = productOrderMapper.listExpiredAmountStatistics(timeType, startDate, endDate);
            for (OpenPositionTotalBean bean : result) {
                if (expiredResult != null && expiredResult.size() > 0) {
                    for (OpenPositionTotalBean averageValueBean : expiredResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime())) {
                            bean.setValue(averageValueBean.getValue().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (OpenPositionTotalBean bean : result) {
                if (bean.getValue() == null) {
                    bean.setValue(BigDecimal.ZERO);
                }
                if (bean.getTotalValue() == null) {
                    bean.setTotalValue(BigDecimal.ZERO);
                }
            }
            if (timeType == 3) {
                for (OpenPositionTotalBean bean : result) {
                    String[] arrs = StringUtils.split(bean.getTime(), MINUS);
                    bean.setTime(UF.getWeekInterval(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1])));
                }
                result.get(0).setTime(StringUtils.split(result.get(0).getTime(), WAVE)[0] + WAVE + endDate);
                result.get(result.size() - 1).setTime(startDate + WAVE + StringUtils.split(result.get(result.size() - 1).getTime(), WAVE)[1]);
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_YEAR, -1);
            String searchEndDate = dateFormat.format(calendar.getTime());
            String searchStartDate = getStartDate(searchEndDate);
            // TODO
            List<KValueBean> temp = new ArrayList<KValueBean>();
            try {
                Date time = dateFormat.parse(searchEndDate);
                Calendar currentCalendar = Calendar.getInstance();
                currentCalendar.setTime(time);
                for (; ; ) {
                    int week = currentCalendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        KValueBean bean = new KValueBean();
                        bean.setTime(dateFormat.format(currentCalendar.getTime()));
                        temp.add(bean);
                    }
                    if (StringUtils.equals(dateFormat.format(currentCalendar.getTime()), searchStartDate)) {
                        break;
                    }
                    currentCalendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }

            double defaultValue = 270;
            List<KValueBean> avgValue = productOrderMapper.listAvgValue(searchStartDate, searchEndDate);
            for (KValueBean kbean : temp) {
                for (KValueBean bean : avgValue) {
                    if (StringUtils.equals(kbean.getTime(), bean.getTime())) {
                        kbean.setMa1(bean.getMa1());
                        break;
                    }
                }
            }
            SerializeObject<List<GoldLatestPriceBean>> priceBeans = priceService.listLatestPrice(searchStartDate, searchEndDate);
            if (priceBeans != null && priceBeans.getData() != null) {
                List<GoldLatestPriceBean> priceData = priceBeans.getData();
                for (KValueBean kbean : temp) {
                    for (GoldLatestPriceBean value : priceData) {
                        if (StringUtils.equals(kbean.getTime(), value.getTime())) {
                            if (kbean.getMa1() == null) {
                                if (value.getLatestpri() != null) {
                                    kbean.setMa1(value.getLatestpri().setScale(2, BigDecimal.ROUND_HALF_UP));
                                } else {
                                    kbean.setMa1(new BigDecimal(defaultValue));
                                }
                            }
                            break;
                        }
                    }
                }
            } else {
                return null;
            }

            List<String> oneDayTime = new ArrayList<String>();
            List<String> fiveDayTime = new ArrayList<String>();
            List<String> twentyTwoDayDayTime = new ArrayList<String>();
            try {
                Date time = dateFormat.parse(searchEndDate);
                Calendar cumCalendar = Calendar.getInstance();
                cumCalendar.setTime(time);
                for (; ; ) {
                    int week = cumCalendar.get(Calendar.DAY_OF_WEEK);
                    if (week != 1 && week != 7) {
                        if (oneDayTime.size() < 1) {
                            oneDayTime.add(dateFormat.format(cumCalendar.getTime()));
                        }
                        if (fiveDayTime.size() < 5) {
                            fiveDayTime.add(dateFormat.format(cumCalendar.getTime()));
                        }
                        if (twentyTwoDayDayTime.size() < 22) {
                            twentyTwoDayDayTime.add(dateFormat.format(cumCalendar.getTime()));
                        } else {
                            break;
                        }
                        if (StringUtils.equals(dateFormat.format(cumCalendar.getTime()), searchStartDate)) {
                            break;
                        }
                    }
                    cumCalendar.add(Calendar.DAY_OF_YEAR, -1);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            double oneDayAmount = 0;
            double fiveDayAmount = 0;
            double twentyTwoDayAmount = 0;
            for (KValueBean priceBean : temp) {
                if (oneDayTime.contains(priceBean.getTime())) {
                    oneDayAmount += priceBean.getMa1().doubleValue();
                }
                if (fiveDayTime.contains(priceBean.getTime())) {
                    fiveDayAmount += priceBean.getMa1().doubleValue();
                }
                if (twentyTwoDayDayTime.contains(priceBean.getTime())) {
                    twentyTwoDayAmount += priceBean.getMa1().doubleValue();
                }
            }
            BigDecimal yestodayAmount = BigDecimal.ZERO;
            if (searchType == 1) {
                yestodayAmount = new BigDecimal(oneDayAmount).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else if (searchType == 2) {
                yestodayAmount = new BigDecimal(fiveDayAmount / 5).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else if (searchType == 3) {
                yestodayAmount = new BigDecimal(twentyTwoDayAmount / 22).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            double totalAmount = 0;
            for (OpenPositionTotalBean bean : result) {
                BigDecimal value = new BigDecimal(bean.getValue().doubleValue() * yestodayAmount.doubleValue()).setScale(2, BigDecimal.ROUND_HALF_UP);
                bean.setValue(value);
                totalAmount += value.doubleValue();
            }

            for (OpenPositionTotalBean bean : result) {
                bean.setTotalValue(new BigDecimal(totalAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
        }
        return result;
    }

    @Override
    public List<OpenPositionTotalBean> listGoldRecordStatistics(int timeType, String startDate, String endDate) {
        List<OpenPositionTotalBean> result = new ArrayList<OpenPositionTotalBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            if (timeType == 1) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                        if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 2) {
                SimpleDateFormat monthFormat = new SimpleDateFormat(NORMAL_MONTH_FORMAT);
                try {
                    Date endDatetime = monthFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    Set<String> info = new HashSet<String>();
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        String value = monthFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(monthFormat.format(calendar.getTime()));
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, monthFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.MONTH, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 3) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week == 1) {
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                    Set<String> info = new HashSet<String>();
                    SimpleDateFormat weekFormat = new SimpleDateFormat("yyyy-ww");
                    for (; ; ) {
                        OpenPositionTotalBean bean = new OpenPositionTotalBean();
                        String value = weekFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(value);
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            List<OpenPositionTotalBean> totalResult = goldRecordMapper.listGoldRecordStatistics(timeType, startDate, endDate);
            BigDecimal totalValue = BigDecimal.ZERO;
            for (OpenPositionTotalBean bean : totalResult) {
                if (bean.getValue() != null) {
                    totalValue = totalValue.add(bean.getValue());
                }
            }
            for (OpenPositionTotalBean bean : result) {
                bean.setTotalValue(totalValue.setScale(5, BigDecimal.ROUND_HALF_UP));
                if (totalResult != null && totalResult.size() > 0) {
                    for (OpenPositionTotalBean averageValueBean : totalResult) {
                        if (StringUtils.equals(bean.getTime(), averageValueBean.getTime())) {
                            bean.setValue(averageValueBean.getValue().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            for (OpenPositionTotalBean bean : result) {
                if (bean.getValue() == null) {
                    bean.setValue(BigDecimal.ZERO);
                }
                if (bean.getTotalValue() == null) {
                    bean.setTotalValue(BigDecimal.ZERO);
                }
            }
            if (timeType == 3) {
                for (OpenPositionTotalBean bean : result) {
                    String[] arrs = StringUtils.split(bean.getTime(), MINUS);
                    bean.setTime(UF.getWeekInterval(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1])));
                }
                result.get(0).setTime(StringUtils.split(result.get(0).getTime(), WAVE)[0] + WAVE + endDate);
                result.get(result.size() - 1).setTime(startDate + WAVE + StringUtils.split(result.get(result.size() - 1).getTime(), WAVE)[1]);
            }
        }
        return result;
    }

    @Override
    public List<TradeTotalAmountBean> listTradeAmountStatistics(int timeType, String startDate, String endDate, List<String> channelIds) {
        List<TradeTotalAmountBean> result = new ArrayList<TradeTotalAmountBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            if (timeType == 1) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    for (; ; ) {
                        TradeTotalAmountBean bean = new TradeTotalAmountBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                        if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 2) {
                SimpleDateFormat monthFormat = new SimpleDateFormat(NORMAL_MONTH_FORMAT);
                try {
                    Date endDatetime = monthFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    Set<String> info = new HashSet<String>();
                    for (; ; ) {
                        TradeTotalAmountBean bean = new TradeTotalAmountBean();
                        String value = monthFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(monthFormat.format(calendar.getTime()));
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, monthFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.MONTH, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 3) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week == 1) {
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                    Set<String> info = new HashSet<String>();
                    SimpleDateFormat weekFormat = new SimpleDateFormat("yyyy-ww");
                    for (; ; ) {
                        TradeTotalAmountBean bean = new TradeTotalAmountBean();
                        String value = weekFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(value);
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            //1.交易总量
            List<TradeTotalAmountBean> tradeResult = productOrderMapper.listTradeAmountStatistics(timeType, startDate, endDate, channelIds);
            double totalTradeAmount = 0;
            if (tradeResult != null && tradeResult.size() > 0) {
                for (TradeTotalAmountBean bean : tradeResult) {
                    if (bean.getTradeAmount() != null) {
                        totalTradeAmount += bean.getTradeAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                }
            }

            //2.回租中交易存量
            List<TradeTotalAmountBean> leasebackResult = productOrderMapper.listLeasebackAmountStatistics(timeType, startDate, endDate, channelIds);
            double regularlyTradeTotalAmount = 0;
            if (leasebackResult != null && leasebackResult.size() > 0) {
                for (TradeTotalAmountBean bean : leasebackResult) {
                    if (bean.getRegularlyTradeAmount() != null) {
                        regularlyTradeTotalAmount += bean.getRegularlyTradeAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                }
            }

            //3.用户持有黄金总量
            List<TradeTotalAmountBean> totalGramResult = productOrderMapper.listTotalGramStatistics(timeType, startDate, endDate, channelIds);
            /*int tbillTotalGram = 0;
            if (totalGramResult != null && totalGramResult.size() > 0) {
                for (TradeTotalAmountBean bean : totalGramResult) {
                    if (bean.getTbillGram() != null) {
                        tbillTotalGram += bean.getTbillGram();
                    }
                }
            }*/

            //4.日增充值金额
            List<TradeTotalAmountBean> rechargeAmountResult = productOrderMapper.listRechargeAmountStatistics(timeType, startDate, endDate, channelIds);
            double rechargeTotalAmount = 0;
            if (rechargeAmountResult != null && rechargeAmountResult.size() > 0) {
                for (TradeTotalAmountBean bean : rechargeAmountResult) {
                    if (bean.getRechargeAmount() != null) {
                        rechargeTotalAmount += bean.getRechargeAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                }
            }

            //5.提现总额
            List<TradeTotalAmountBean> withdrawAmountResult = productOrderMapper.listWithdrawAmountStatistics(timeType, startDate, endDate, channelIds);
            double withdrawTotalAmount = 0;
            if (withdrawAmountResult != null && withdrawAmountResult.size() > 0) {
                for (TradeTotalAmountBean bean : withdrawAmountResult) {
                    if (bean.getWithdrawAmount() != null) {
                        withdrawTotalAmount += bean.getWithdrawAmount().setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }
                }
            }


            for (TradeTotalAmountBean bean : result) {
                //总计
                bean.setTradeTotalAmount(new BigDecimal(totalTradeAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                bean.setRegularlyTradeTotalAmount(new BigDecimal(regularlyTradeTotalAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                //不统计用户持有黄金总量
                bean.setTbillTotalGram(0);
                bean.setRechargeTotalAmount(new BigDecimal(rechargeTotalAmount).setScale(5, BigDecimal.ROUND_HALF_UP));
                bean.setWithdrawTotalAmount(new BigDecimal(withdrawTotalAmount).setScale(5, BigDecimal.ROUND_HALF_UP));

                if (tradeResult != null && tradeResult.size() > 0) {
                    //循环每个日期
                    for (TradeTotalAmountBean tradeBean : tradeResult) {
                        if (StringUtils.equals(bean.getTime(), tradeBean.getTime()) && tradeBean.getTradeAmount() != null) {
                            bean.setTradeAmount(tradeBean.getTradeAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }

                    }

                    for (TradeTotalAmountBean leasebackBean : leasebackResult) {
                        if (StringUtils.equals(bean.getTime(), leasebackBean.getTime()) && leasebackBean.getRegularlyTradeAmount() != null) {
                            bean.setRegularlyTradeAmount(leasebackBean.getRegularlyTradeAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                        }
                    }

                    //用户持有黄金总量
                    for (TradeTotalAmountBean leasebackBean : totalGramResult) {
                        if (StringUtils.equals(bean.getTime(), leasebackBean.getTime()) && leasebackBean.getTbillGram() != null) {
                            bean.setTbillGram(leasebackBean.getTbillGram());
                        }
                    }

                    //日增充值金额
                    for (TradeTotalAmountBean leasebackBean : rechargeAmountResult) {
                        if (StringUtils.equals(bean.getTime(), leasebackBean.getTime()) && leasebackBean.getRechargeAmount() != null) {
                            bean.setRechargeAmount(leasebackBean.getRechargeAmount());
                        }
                    }

                    //日提现总额
                    for (TradeTotalAmountBean leasebackBean : withdrawAmountResult) {
                        if (StringUtils.equals(bean.getTime(), leasebackBean.getTime()) && leasebackBean.getWithdrawAmount() != null) {
                            bean.setWithdrawAmount(leasebackBean.getWithdrawAmount());
                        }
                    }
                }
            }
            for (TradeTotalAmountBean bean : result) {
                if (bean.getTradeAmount() == null) {
                    bean.setTradeAmount(BigDecimal.ZERO);
                }
                if (bean.getRegularlyTradeAmount() == null) {
                    bean.setRegularlyTradeAmount(BigDecimal.ZERO);
                }

                if (bean.getTbillGram() == null) {
                    bean.setTbillGram(0);
                }

                if (bean.getRechargeAmount() == null) {
                    bean.setRechargeAmount(BigDecimal.ZERO);
                }

                if (bean.getWithdrawAmount() == null) {
                    bean.setWithdrawAmount(BigDecimal.ZERO);
                }
            }
            if (timeType == 3) {
                for (TradeTotalAmountBean bean : result) {
                    String[] arrs = StringUtils.split(bean.getTime(), MINUS);
                    bean.setTime(UF.getWeekInterval(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1])));
                }
                result.get(0).setTime(StringUtils.split(result.get(0).getTime(), WAVE)[0] + WAVE + endDate);
                result.get(result.size() - 1).setTime(startDate + WAVE + StringUtils.split(result.get(result.size() - 1).getTime(), WAVE)[1]);
            }
        }
        return result;
    }

    @Override
    public List<TradeTotalStatisticsBean> listTradeTotalStatistics(int timeType, String startDate, String endDate, List<String> channelIds,List<Integer> productType) {
        List<TradeTotalStatisticsBean> result = new ArrayList<TradeTotalStatisticsBean>();
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            if (timeType == 1) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    for (; ; ) {
                        TradeTotalStatisticsBean bean = new TradeTotalStatisticsBean();
                        bean.setTime(dateFormat.format(calendar.getTime()));
                        result.add(bean);
                        if (StringUtils.equals(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 2) {
                SimpleDateFormat monthFormat = new SimpleDateFormat(NORMAL_MONTH_FORMAT);
                try {
                    Date endDatetime = monthFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    Set<String> info = new HashSet<String>();
                    for (; ; ) {
                        TradeTotalStatisticsBean bean = new TradeTotalStatisticsBean();
                        String value = monthFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(monthFormat.format(calendar.getTime()));
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, monthFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.MONTH, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else if (timeType == 3) {
                SimpleDateFormat dateFormat = new SimpleDateFormat(NORMAL_DATE_FORMAT);
                try {
                    Date endDatetime = dateFormat.parse(endDate);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(endDatetime);
                    int week = calendar.get(Calendar.DAY_OF_WEEK);
                    if (week == 1) {
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                    Set<String> info = new HashSet<String>();
                    SimpleDateFormat weekFormat = new SimpleDateFormat("yyyy-ww");
                    for (; ; ) {
                        TradeTotalStatisticsBean bean = new TradeTotalStatisticsBean();
                        String value = weekFormat.format(calendar.getTime());
                        if (!info.contains(value)) {
                            info.add(value);
                            bean.setTime(value);
                            result.add(bean);
                        }
                        if (StringUtils.startsWith(startDate, dateFormat.format(calendar.getTime()))) {
                            break;
                        }
                        calendar.add(Calendar.DAY_OF_YEAR, -1);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }

            //购买总交易金额、克重
            List<TradeTotalStatisticsBean> buyTotalAmountResult = productOrderMapper.listBuyTotalStatistics(timeType, startDate, endDate, channelIds,productType);

            //回租总交易金额、克重
            List<TradeTotalStatisticsBean> leasebackTotalResult = productOrderMapper.listLeasebackTotalStatistics(timeType, startDate, endDate, channelIds,productType);

            //出售总交易金额、克重
            List<TradeTotalStatisticsBean> soldTotalResult = productOrderMapper.listSoldTotalStatistics(timeType, startDate, endDate, channelIds,productType);

            //购买营销红包总金额、克重
            List<TradeTotalStatisticsBean> BuyMarketingResult = productOrderMapper.listBuyMarketingStatistics(timeType, startDate, endDate, channelIds,productType);

            //回租营销红包总交易金额、克重
            List<TradeTotalStatisticsBean> leasebackMarketingResult = productOrderMapper.listLeasebackMarketingStatistics(timeType, startDate, endDate, channelIds,productType);



            for (TradeTotalStatisticsBean bean : result) {
                bean.setBuyTotalGram(0);
                bean.setBuyTotalAmount(BigDecimal.ZERO);
                bean.setLeasebackTotalIncomeGram(0);
                bean.setLeasebackTotalIncomeAmount(BigDecimal.ZERO);
                bean.setLeasebackTotalGram(0);
                bean.setLeasebackTotalAmount(BigDecimal.ZERO);
                bean.setSoldTotalGram(0);
                bean.setSoldTotalAmount(BigDecimal.ZERO);
                bean.setSoldTotalIncomeAmount(BigDecimal.ZERO);
                bean.setMarketingTotalGram(BigDecimal.ZERO);
                bean.setMarketingTotalAmount(BigDecimal.ZERO);

                if (!CollectionUtils.isEmpty(buyTotalAmountResult)) {
                    for (TradeTotalStatisticsBean buyTotalBean : buyTotalAmountResult) {
                        if (StringUtils.equals(bean.getTime(), buyTotalBean.getTime())) {
                            if (buyTotalBean.getBuyTotalAmount() != null) {
                                bean.setBuyTotalAmount(buyTotalBean.getBuyTotalAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                            }
                            if (buyTotalBean.getBuyTotalGram() != null) {
                                bean.setBuyTotalGram(buyTotalBean.getBuyTotalGram());
                            }
                        }
                    }
                }

                if (!CollectionUtils.isEmpty(leasebackTotalResult)) {
                    for (TradeTotalStatisticsBean leasebackBean : leasebackTotalResult) {
                        if (StringUtils.equals(bean.getTime(),leasebackBean.getTime())){
                            if (leasebackBean.getLeasebackTotalAmount() != null) {
                                bean.setLeasebackTotalAmount(leasebackBean.getLeasebackTotalAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                            }
                            if (leasebackBean.getLeasebackTotalGram() != null) {
                                bean.setLeasebackTotalGram(leasebackBean.getLeasebackTotalGram());
                            }
                            if (leasebackBean.getLeasebackTotalIncomeAmount() != null) {
                                bean.setLeasebackTotalIncomeAmount(leasebackBean.getLeasebackTotalIncomeAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                            }
                            if (leasebackBean.getLeasebackTotalIncomeGram() != null) {
                                bean.setLeasebackTotalIncomeGram(leasebackBean.getLeasebackTotalIncomeGram());
                            }
                        }
                    }
                }

                if (!CollectionUtils.isEmpty(soldTotalResult)) {
                    for (TradeTotalStatisticsBean soldBean : soldTotalResult) {
                        if (StringUtils.equals(bean.getTime(),soldBean.getTime())){
                            if (soldBean.getSoldTotalAmount() != null) {
                                bean.setSoldTotalAmount(soldBean.getSoldTotalAmount().setScale(5, BigDecimal.ROUND_HALF_UP));
                            }
                            if (soldBean.getSoldTotalGram() != null) {
                                bean.setSoldTotalGram(soldBean.getSoldTotalGram());
                            }
                            if (soldBean.getSoldTotalIncomeAmount() != null) {
                                bean.setSoldTotalIncomeAmount(soldBean.getSoldTotalIncomeAmount());
                            }
                        }
                    }
                }

                if (!CollectionUtils.isEmpty(BuyMarketingResult)) {
                    for (TradeTotalStatisticsBean buyMarkBean : BuyMarketingResult) {
                        if (StringUtils.equals(bean.getTime(),buyMarkBean.getTime())){
                            if (buyMarkBean.getMarketingTotalAmount() != null) {
                                bean.setMarketingTotalAmount(buyMarkBean.getMarketingTotalAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
                            }
                            if (buyMarkBean.getMarketingTotalGram() != null) {
                                bean.setMarketingTotalGram(buyMarkBean.getMarketingTotalGram());
                            }
                        }
                    }
                }

                if (!CollectionUtils.isEmpty(leasebackMarketingResult)) {
                    for (TradeTotalStatisticsBean leasebackMarkBean : leasebackMarketingResult) {
                        if (StringUtils.equals(bean.getTime(),leasebackMarkBean.getTime())){
                            if (leasebackMarkBean.getMarketingTotalAmount() != null) {
                                bean.setMarketingTotalAmount(bean.getMarketingTotalAmount().add(leasebackMarkBean.getMarketingTotalAmount()).setScale(2, BigDecimal.ROUND_HALF_UP));
                            }
                            if (leasebackMarkBean.getMarketingTotalGram() != null) {
                                bean.setMarketingTotalGram(bean.getMarketingTotalGram().add(leasebackMarkBean.getMarketingTotalGram()).setScale(5, BigDecimal.ROUND_HALF_UP));
                            }
                        }
                    }
                }

            }

            if (timeType == 3) {
                for (TradeTotalStatisticsBean bean : result) {
                    String[] arrs = StringUtils.split(bean.getTime(), MINUS);
                    bean.setTime(UF.getWeekInterval(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1])));
                }
                result.get(0).setTime(StringUtils.split(result.get(0).getTime(), WAVE)[0] + WAVE + endDate);
                result.get(result.size() - 1).setTime(startDate + WAVE + StringUtils.split(result.get(result.size() - 1).getTime(), WAVE)[1]);
            }
        }
        return result;
    }

    @Override
    public boolean updatePayStatus(int payStatus, String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return false;
        }
        return productOrderMapper.updatePayStatus(payStatus, orderId) > 0 ? true : false;
    }

    @Override
    @RemoveCache(cleanSearch = true)
    @Transactional(rollbackFor = Exception.class)
    public String save(ProductOrderBean entityBean) {
        // 数据完整性校验0
        if (null == entityBean || StringUtils.isBlank(entityBean.getMemberId()) ||
                StringUtils.isBlank(entityBean.getProductId())) {
            Ensure.that(true).isTrue("00000002");
        }
        // 获取产品资料
        SerializeObject<ProductFindBean> obj = productService.queryProductById(entityBean.getProductId());
        if (null == obj || obj.getCode() != ResultType.NORMAL) {
            Ensure.that(true).isTrue("17000601");
        }
        ProductFindBean productBean = obj.getData();
        // 判断是否有效交易时间段 20180430 新增限制
        SerializeObject o = productService.findIsBuy(entityBean.getProductId());
        if (null == o || ResultType.NORMAL != o.getCode()) {
            Ensure.that(true).isTrue(o.getMsg());
        }
        if (productBean.getType() == 1) {
            int num = productOrderMapper.countTodayNoviceOrders();
            if (num >= 1000) {
                Ensure.that(true).isTrue("17000721");
            }
        }
        if (productBean.getShelfState() == 2) {
            Ensure.that(true).isTrue("17000720");
        }
        //if (productBean.get)
        if (PayType.TURN_INTO.getValue().equals(entityBean.getPayType())) {
            int num = productOrderMapper.countActivityOrders(entityBean.getMemberId(), productBean.getId());
            if (num > 0) {
                Ensure.that(true).isTrue("17002013");
            }
        }
        String key = "ProductOrderServiceImpl:save:" + entityBean.getMemberId() + ":" + entityBean.getProductId();
        if (!redisGlobalLock.lock(key)) {
            Ensure.that(true).isTrue("17000714");
        }
        try {
            ProductOrder entity = dozerBeanMapper.map(entityBean, ProductOrder.class);
            if (StringUtils.isBlank(entity.getId())) {
                entity.setId(UF.getRandomUUID());
            }

            // 如果是新手专享，统计改用户之前有没有购买过
            if (ProductTypeEnum.NOVICE.getType() == productBean.getType()) {
                // 统计已支付
                int investTimes = countQuery(
                        entityBean.getMemberId(),
                        ProductTypeEnum.NOVICE.getType(),
                        ProductOrderPayStatus.COMPLETE.getValue(),
                        null).intValue();
                if (investTimes > 0) {
                    Ensure.that(true).isTrue("17000713");
                }
                // 统计待支付
                investTimes = countQuery(
                        entityBean.getMemberId(),
                        ProductTypeEnum.NOVICE.getType(),
                        ProductOrderPayStatus.WAIT.getValue(),
                        null).intValue();
                if (investTimes > 0) {
                    Ensure.that(true).isTrue("17000713");
                }
            }

            // 订单号
            if (StringUtils.isBlank(entity.getOrderId())) {
                entity.setOrderId(SerialNumberWorker.getInstance().nextId());
            }
            // 产品名称
            entity.setProductName(productBean.getName());
            // 产品类型 1:新手专享 2:活动产品  3:活期产品 4:定期产品
            entity.setType(productBean.getType());
            // 年化收益 **/
            entity.setYearsIncome(productBean.getYearsIncome());
            // 投资期限 **/
            entity.setInvestDay(productBean.getInvestDay());
            if (1 == productBean.getSettingPriceType()) {
                SerializeObject serializeObject = priceService.currentGoldPrice();
                if (null == serializeObject || serializeObject.getCode() != ResultType.NORMAL) {
                    Ensure.that(true).isTrue("17000708");
                }
                BigDecimal goldPrice = new BigDecimal(serializeObject.getData().toString());
                entity.setGoldPrice(goldPrice);
            } else {
                // 自定义价格
                entity.setGoldPrice(productBean.getSettingPrice());
            }
            // 黄金买入手续费 && 现金购买
            BigDecimal fee = BigDecimal.ZERO;
            if (!PayType.TURN_INTO.getValue().equals(entity.getPayType())) {
                SerializeObject rateBean = rateSettingsService.get(RateKeyEnum.BUY_GOLD.getKey());
                getLog().info("买金参数：" + JSON.toJSONString(rateBean));
                if (rateBean != null && rateBean.getData() != null) {
                    JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
                    int dayNum = productOrderMapper.getTransactionNumForThisDay(entityBean.getMemberId());
                    int monthNum = productOrderMapper.getTransactionNumForThisMonth(entityBean.getMemberId());
                    if (entityBean.getBuyType() == 2) {
                        BigDecimal itemAmount = entityBean.getActualAmount();
                        fee = fundRateConfig.getFee(json, itemAmount, dayNum, monthNum);
                    } else {
                        BigDecimal itemAmount = entity.getAmount().multiply(entity.getGoldPrice());
                        fee = fundRateConfig.getFee(json, itemAmount, dayNum, monthNum);
                    }
                }
            }
            getLog().info("买金手续费：" + fee);
            entity.setFee(fee);

            // 购买类型 1:按克重 2:按金额
            if (entityBean.getBuyType() == 2) {
                // 按金额购买 ======================================
                // 支付金额
                BigDecimal itemAmount = entityBean.getActualAmount();
                entity.setItemAmount(itemAmount);
                // 支付金额（商品总价+手续费）
                BigDecimal actualAmount = BigDecimalUtil.add(entity.getItemAmount(), entity.getFee());
                entity.setActualAmount(actualAmount);
                // 购买克重 = 金额 / 金价
                entity.setAmount(BigDecimalUtil.to5Point(itemAmount.divide(entity.getGoldPrice(), 10, ROUND_HALF_UP)));

                if (!BigDecimalUtil.isZeroOrNull(productBean.getPriceMin()) && productBean.getPriceMin().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果小于最低限额
                    error("getPriceMin:" + productBean.getPriceMin() + " | " + "getItemAmount:" + entity.getItemAmount());
                    boolean isOk = (entity.getItemAmount().compareTo(productBean.getPriceMin()) < 0);
                    Ensure.that(isOk).isTrue("17000711");
                }
                if (!BigDecimalUtil.isZeroOrNull(productBean.getPriceMax()) && productBean.getPriceMax().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果大于最高限额
                    error("getPriceMax:" + productBean.getPriceMax() + " | " + "getItemAmount:" + entity.getItemAmount());
                    boolean isOk = (entity.getItemAmount().compareTo(productBean.getPriceMax()) > 0);
                    Ensure.that(isOk).isTrue("17000712");
                }
            } else {
                // 按克重购买 ======================================
                // 商品总价 (克重 * 金价)
                BigDecimal itemAmount = entity.getAmount().multiply(entity.getGoldPrice());
                entity.setItemAmount(itemAmount);

                // 支付金额（商品总价+手续费）
                BigDecimal actualAmount = BigDecimalUtil.add(entity.getItemAmount(), entity.getFee());
                entity.setActualAmount(actualAmount);

                if (!BigDecimalUtil.isZeroOrNull(productBean.getGramMin()) && productBean.getGramMin().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果小于最低限额
                    error("getGramMin:" + productBean.getGramMin() + " | " + "getAmount:" + entity.getAmount());
                    boolean isOk = (entity.getAmount().compareTo(productBean.getGramMin()) < 0);
                    Ensure.that(isOk).isTrue("17000711");
                }
                if (!BigDecimalUtil.isZeroOrNull(productBean.getGramMax()) && productBean.getGramMax().compareTo(BigDecimal.ZERO) > 0) {
                    // 如果大于最高限额
                    error("getGramMax:" + productBean.getGramMax() + " | " + "getAmount:" + entity.getAmount());
                    boolean isOk = (entity.getAmount().compareTo(productBean.getGramMax()) > 0);
                    Ensure.that(isOk).isTrue("17000712");
                }
            }
            double lowestQuota = 0;
            if (productBean.getRaiseGram().doubleValue() > 0) {
                double toRasizeGram = 0;
                if (productBean.getToRaiseGram() != null) {
                    toRasizeGram = productBean.getToRaiseGram().doubleValue();
                }
                SerializeObject<List<DataDictionaryBean>> beans = dataDictionaryService.findListByClassification(GOLD_WEIGHT_RANGE, 1);
                if (beans == null || beans.getData() == null || beans.getData().size() != 2) {
                    Ensure.that(true).isTrue("17000719");
                }
                double value0 = Double.parseDouble(beans.getData().get(0).getItemValue());
                double value1 = Double.parseDouble(beans.getData().get(1).getItemValue());
                if (value0 > value1) {
                    lowestQuota = productBean.getRaiseGram().doubleValue() * value1 / 100;
                    double totalGram = productBean.getRaiseGram().doubleValue() * value0 / 100;
                    if ((toRasizeGram + entity.getAmount().doubleValue()) > totalGram) {
                        Ensure.that(true).isTrue("17000719");
                    }
                } else {
                    lowestQuota = productBean.getRaiseGram().doubleValue() * value0 / 100;
                    double totalGram = productBean.getRaiseGram().doubleValue() * value1 / 100;
                    if ((toRasizeGram + entity.getAmount().doubleValue()) > totalGram) {
                        Ensure.that(true).isTrue("17000719");
                    }
                }
            }

            // 判断购买克重和金额是否符合产品限定 ========================================================
            if (BigDecimalUtil.isZeroOrNull(entity.getItemAmount()) || entity.getItemAmount().compareTo(BigDecimal.ZERO) < 0 ||
                    BigDecimalUtil.isZeroOrNull(entity.getAmount()) || entity.getAmount().compareTo(BigDecimal.ZERO) < 0
                    ) {
                // 如果商品总价<=0 或者 购买克重<=0
                Ensure.that(true).isTrue("17000711");
            }

            // 预期收益
            entity.setIncomeAmount(calculateIncomeAmount(entity.getAmount(), UF.toInt(entity.getInvestDay()), entity.getYearsIncome()));
            // 如果是活期，没有收益
            if (ProductTypeEnum.CURRENT.getType() == entity.getType()) {
                entity.setIncomeAmount(BigDecimal.ZERO);
            }

            // 计息时间（购买时间 + 计息日[T+2]）
            LocalDateTime startTime = UF.getDateTime(UF.getFormatDateNow()).plusDays(productBean.getInterestAccrualDay());
            entity.setStartTime(startTime);
            // 到期时间（计息时间 + 投资期限）
            LocalDateTime endTime = startTime.plusDays(UF.toInt(entity.getInvestDay()));
            entity.setEndTime(endTime);

            // 支付状态  1:待支付 2:已支付 3:已过期
            entity.setPayStatus(WAIT.getValue());
            // 产品状态  1:未到期 2:已到期
            entity.setStatus(NOT_EXPIRED.getValue());

            // 支付截止时间 (当前时间 + 10分钟)
            SerializeObject resultRate = rateSettingsService.get(RateKeyEnum.UNPAID_TIME.getKey());
            if (resultRate.getData() != null) {
                Map<String, Object> resultRateMap = (Map<String, Object>) resultRate.getData();
                LocalDateTime stopPayTime = UF.getDateTime().plusMinutes((Integer) resultRateMap.get(RateKeyEnum.UNPAID_TIME.getKey()));
                entity.setStopPayTime(stopPayTime);
            }

            // 2、如果是金柚宝转入========================================
            if (PayType.TURN_INTO.getValue().equals(entity.getPayType())) {
                BigDecimal todayBuyAmount = productOrderMapper.sumToadySuccessAmount(entityBean.getMemberId());
                if (null == todayBuyAmount) {
                    todayBuyAmount = BigDecimal.ZERO;
                }
                todayBuyAmount = BigDecimalUtil.add(todayBuyAmount, entity.getAmount());
                SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.BUY_SELL_GRAM.getKey());
                //if (fundRateConfig.getMaxBuyWeightPerDay().compareTo(todayBuyAmount) < 0) {
                if (serializeObject.getData() != null) {
                    Map<String, Object> map = (Map<String, Object>) serializeObject.getData();
                    String maxGramPerday = String.valueOf(map.get(BUY_MAX_GRAM_PERDAY));
                    if (new BigDecimal(maxGramPerday).compareTo(todayBuyAmount) < 0
                            && !"0".equals(maxGramPerday)) {
                        Ensure.that(true).isTrue("17000715");
                    }
                }

                // 2.1、设置支付状态为已支付、已到期 ======================================
                entity.setPayStatus(COMPLETE.getValue());
                // 手续费
                entity.setFee(BigDecimal.ZERO);

                // 2.2、支付详情(按购买克重支付) ======================================
                BigDecimal[] payAmount = memberGoldService.payAmount(entity.getMemberId(), entity.getAmount(), BillGoldTradeType.DEMAND_TO_TERM, entity.getGoldPrice(), BigDecimal.ZERO);
                // 如果为null则不足以支付
                Ensure.that(null == payAmount).isTrue("17000707");
                // 支付金额
                entity.setActualAmount(BigDecimal.ZERO);
                // T-1日利息
                entity.setInterestHistoryAmount(payAmount[1]);
                // T日本金
                entity.setPrincipalNowAmount(payAmount[2]);
                // T-1日本金
                entity.setPrincipalHistoryAmount(payAmount[3]);

                // 2.3、调整会员资产账户信息【冻结资产】 ======================================
                memberGoldService.freezeAmount(entity.getMemberId(), entity.getAmount(), entity.getIncomeAmount());
                productService.addToRaiseGram(productBean.getId(), entity.getAmount());
                if (productBean.getRaiseGram().doubleValue() > 0) {
                    double hadRaisedGram = productBean.getToRaiseGram().doubleValue() + entity.getAmount().doubleValue();
                    if (hadRaisedGram >= lowestQuota) {
                        productService.updateShelfState(productBean.getId(), 2);
                        SerializeObject<List<DataDictionaryBean>> beans = dataDictionaryService.findListByClassification(cn.ug.msg.bean.status.CommonConstants.MsgType.PRODUCT_DOWN_SHELF.getName(), 1);
                        if (beans != null && beans.getData() != null) {
                            List<DataDictionaryBean> data = beans.getData();
                            if (data != null && data.size() > 0) {
                                for (DataDictionaryBean bean : data) {
                                    Sms sms = new Sms();
                                    sms.setPhone(bean.getItemValue());
                                    sms.setType(SmsType.SOLD_OUT);
                                    Map<String, String> paramMap = new HashMap<>(2);
                                    paramMap.put("produtName", productBean.getName());
                                    paramMap.put("hour", String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)));
                                    sms.setParamMap(paramMap);
                                    amqpTemplate.convertAndSend(QUEUE_MSG_SMS_SEND, sms);
                                }
                            }
                        }
                    }
                }

                wxSend(entity.getMemberId(), productBean.getName(), entity.getOrderId(), entity.getGoldPrice(), entity.getActualAmount(), entity.getAmount(), entity);
                MemberAccountBean memberAccountBean = memberAccountService.findByMemberId(entity.getMemberId());
                /**
                 * 微信服务号消息推送  收支变动
                 */
                WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
                wxMessageParamBean.setMemberId(entity.getMemberId());
                wxMessageParamBean.setType(WxTemplateEnum.FUND_CHANGE.getType());
                WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.FUND_CHANGE.getType());
                WxNotifyData wxNotifyData = new WxNotifyData();

                Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
                WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
                first.setDataValue(wxTemplateEnum.getFirstData());
                wxParamMap.put("first", first);

                WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
                keyword1.setDataValue(PayTypeEnum.BUY_GOLD.getMsg());
                wxParamMap.put("keyword1", keyword1);

                WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
                keyword2.setDataValue(BigDecimalUtil.to2Point(entity.getActualAmount()).toString());
                wxParamMap.put("keyword2", keyword2);

                WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
                keyword3.setDataValue(DateUtils.dateToStr(new Date(), DateUtils.patter));
                wxParamMap.put("keyword3", keyword3);

                WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
                keyword4.setDataValue(BigDecimalUtil.to2Point(memberAccountBean.getUsableAmount()).toString());
                wxParamMap.put("keyword4", keyword4);

                WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
                remark.setDataValue(wxTemplateEnum.getRemark());
                wxParamMap.put("remark", remark);

                wxNotifyData.setData(wxParamMap);
                wxMessageParamBean.setTemplateData(wxNotifyData);
                amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
            }

            int rows = productOrderMapper.insert(entity);
            Ensure.that(rows).isLt(1, "00000005");


            if (WAIT.getValue().equals(entity.getPayType())) {
                // 待支付短信提醒
                // 如果不是活期产品, 2018-03-24确定所以产品都使用待支付提醒
                msgByWaitPay(entity.getMemberId());
            }
            if (COMPLETE.getValue().equals(entity.getPayType())) {
                // 支付完成短信提醒（金柚宝转入）
                msgByBuyGold(entity.getId());
                msgByTurnInto(entity.getMemberId(), entity.getProductName(), entity.getAmount(), entity.getInvestDay(), entity.getAmount());
                // 投资返利
                rewardsByCompletePay(entity.getId());
                // 生成e签宝合同
                esignAfterCompletePay(entity, productBean.getIsActivity());
            }
            return entity.getId();
        } catch (Exception e) {
            error("创建投资记录失败", e);
            throw e;
        } finally {
            redisGlobalLock.unlock(key);
        }
    }

    @Override
    @RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
    public int delete(String id) {
        if (StringUtils.isBlank(id)) {
            return 0;
        }

        return productOrderMapper.delete(id);
    }

    @Override
    @RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
    public int deleteByIds(String[] id) {
        if (id == null || id.length <= 0) {
            return 0;
        }

        return productOrderMapper.deleteByIds(id);
    }

    @Override
    @RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
    public int removeByIds(String[] id) {
        if (id == null || id.length <= 0) {
            return 0;
        }

        return productOrderMapper.updateByPrimaryKeySelective(
                getParams()
                        .put("id", id)
                        .put("deleted", DeleteStatus.YES)
                        .toMap()
        );
    }

    @Override
    @SaveCache(cacheType = OBJECT)
    public ProductOrderBean findById(String id) {
        if (StringUtils.isBlank(id)) {
            return null;
        }

        ProductOrder entity = productOrderMapper.findById(id);
        if (null == entity) {
            return null;
        }

        ProductOrderBean entityBean = dozerBeanMapper.map(entity, ProductOrderBean.class);
        entityBean.setStartTimeString(UF.getFormatDateTime(entity.getStartTime()));
        entityBean.setEndTimeString(UF.getFormatDateTime(entity.getEndTime()));
        entityBean.setStopPayTimeString(UF.getFormatDateTime(entity.getStopPayTime()));
        entityBean.setAddTimeString(UF.getFormatDateTime(entity.getAddTime()));
        entityBean.setModifyTimeString(UF.getFormatDateTime(entity.getModifyTime()));
        entityBean.setProductOrderFeeBean(findFeeByOrderId(entity.getOrderId()));
        SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.UNPAID_TIME.getKey());
        //if (fundRateConfig.getMaxBuyWeightPerDay().compareTo(todayBuyAmount) < 0) {
        if (serializeObject.getData() != null) {
            Map<String, Object> map = (Map<String, Object>) serializeObject.getData();
            entityBean.setUnpaidTimeMinute((Integer) map.get(RateKeyEnum.UNPAID_TIME.getKey()));
        }
        SerializeObject<ProductFindBean> obj = productService.queryProductById(entityBean.getProductId());
        if (obj != null || obj.getCode() == ResultType.NORMAL) {
            ProductFindBean product = obj.getData();
            entityBean.setIsActivity(product.getIsActivity());
        }
        return entityBean;
    }

    @Override
    @SaveCache(cacheType = SEARCH)
    public ProductOrderBean findByOrderId(String orderId) {
        List<ProductOrderBean> list = query(null, null, orderId, null, null, null, null, null, null, null,
                null, null, null, null,
                null, null, null, null, null, null);
        if (null == list || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    @Override
    @SaveCache(cacheType = SEARCH)
    public DataTable<ProductOrderBean> query(String order, String sort, int pageNum, int pageSize, List<Integer> typeList,
                                             Integer payStatus, Integer status, Boolean overEndTime, BigDecimal amountMin, BigDecimal amountMax,
                                             LocalDateTime addTimeMin, LocalDateTime addTimeMax, String memberId, String memberName, String memberMobile,
                                             String productId, String keyword, String channelId) {
        Page<ProductOrderBean> page = PageHelper.startPage(pageNum, pageSize);
        List<ProductOrderBean> list = query(order, sort, null, null, typeList, null, payStatus, status, null, overEndTime,
                amountMin, amountMax, addTimeMin, addTimeMax,
                memberId, memberName, memberMobile, productId, keyword, channelId);
        return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), list);
    }

    @Override
    public List<ProductOrderBean> query(String order, String sort, List<Integer> typeList, Integer payStatus, Integer status, Boolean overEndTime,
                                        BigDecimal amountMin, BigDecimal amountMax, LocalDateTime addTimeMin, LocalDateTime addTimeMax,
                                        String memberId, String memberName, String memberMobile, String productId, String keyword, String channelId) {
        return query(order, sort, null, null, typeList, null, payStatus, status, null, overEndTime,
                amountMin, amountMax, addTimeMin, addTimeMax,
                memberId, memberName, memberMobile, productId, keyword, channelId);
    }

    @Override
    public List<ProductOrderBean> queryBecomeDueOrders() {
        List<ProductOrderBean> dataList = new ArrayList<>();
        Map<String, Object> params = new HashMap<String, Object>();
        List<ProductOrder> list = productOrderMapper.queryBecomeDueOrders();
        for (ProductOrder o : list) {
            ProductOrderBean objBean = dozerBeanMapper.map(o, ProductOrderBean.class);
            objBean.setStartTimeString(UF.getFormatDateTime(o.getStartTime()));
            objBean.setEndTimeString(UF.getFormatDateTime(o.getEndTime()));
            objBean.setStopPayTimeString(UF.getFormatDateTime(o.getStopPayTime()));
            objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
            objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
            objBean.setProductOrderFeeBean(findFeeByOrderId(o.getOrderId()));
            dataList.add(objBean);
        }
        return dataList;
    }

    @Override
    @SaveCache(cacheType = SEARCH)
    public DataTable<ProductOrderSummaryBean> queryByProductId(String order, String sort, int pageNum, int pageSize, String productId) {
        Page<ProductOrderSummaryBean> page = PageHelper.startPage(pageNum, pageSize);
        // 全部支付状态
        Integer payStatus = ProductOrderPayStatus.COMPLETE.getValue();
        // 全部产品状态
        Integer status = null;

        List<ProductOrderBean> list = query(order, sort, null, null, null, null, payStatus, status, null, null,
                null, null, null, null,
                null, null, null, productId, null, null);

        List<ProductOrderSummaryBean> dataList = new ArrayList<>();
        for (ProductOrderBean o : list) {
            ProductOrderSummaryBean summaryBean = dozerBeanMapper.map(o, ProductOrderSummaryBean.class);
            // 隐藏手机号码， 格式化日期
            summaryBean.setMemberMobile(UF.getFormatMobile(o.getMemberMobile()));

            dataList.add(summaryBean);
        }

        return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), dataList);
    }

    @Override
    public List<ProductOrderSummaryBean> queryByProductId(int offset, int size, String productId, int productType) {
        if (StringUtils.isNotBlank(productId)) {
            List<ProductOrderSummaryBean> result = new ArrayList<ProductOrderSummaryBean>();
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("productId", productId);
            params.put("productType", productType);
            params.put("offset", offset);
            params.put("size", size);
            List<ProductOrder> list = productOrderMapper.queryProductOrders(params);
            if (list != null && list.size() > 0) {
                List<ProductOrderBean> dataList = new ArrayList<>();
                for (ProductOrder o : list) {
                    ProductOrderBean objBean = dozerBeanMapper.map(o, ProductOrderBean.class);
                    objBean.setStartTimeString(UF.getFormatDateTime(o.getStartTime()));
                    objBean.setEndTimeString(UF.getFormatDateTime(o.getEndTime()));
                    objBean.setStopPayTimeString(UF.getFormatDateTime(o.getStopPayTime()));
                    objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
                    objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
                    objBean.setProductOrderFeeBean(findFeeByOrderId(o.getOrderId()));
                    dataList.add(objBean);
                }
                for (ProductOrderBean o : dataList) {
                    ProductOrderSummaryBean summaryBean = dozerBeanMapper.map(o, ProductOrderSummaryBean.class);
                    summaryBean.setMemberMobile(UF.getFormatMobile(o.getMemberMobile()));

                    result.add(summaryBean);
                }
            }
            return result;
        }
        return null;
    }

    @Override
    public int countByProductId(String productId, int productType) {
        if (StringUtils.isNotBlank(productId)) {
            return productOrderMapper.countProductOrders(productId, productType);
        }
        return 0;
    }

    @Override
    @RemoveCache(cleanAll = true)
    public int updatePayStatus(String[] id, ProductOrderPayStatus payStatus) {
        if (id == null || id.length <= 0) {
            return 0;
        }

        return productOrderMapper.updateByPrimaryKeySelective(
                getParams()
                        .put("id", id)
                        .put("payStatus", payStatus.getValue())
                        .toMap()
        );
    }

    @Override
    @RemoveCache(cleanAll = true)
    public int updateStatus(String[] id, ProductOrderStatus status) {
        if (id == null || id.length <= 0) {
            return 0;
        }

        return productOrderMapper.updateByPrimaryKeySelective(
                getParams()
                        .put("id", id)
                        .put("status", status.getValue())
                        .toMap()
        );
    }

    @Override
    @RemoveCache(cleanAll = true)
    public int expiredProductOrder() {
        // 查询 待支付 && 超时
        List<ProductOrderBean> list = query(null, null, null, null, null, null, WAIT.getValue(), null, true, null,
                null, null, null, null, null, null, null, null, null, null);

        if (null == list || list.isEmpty()) {
            return 0;
        }
        List<String> idList = new ArrayList<>();
        for (ProductOrderBean o : list) {
            idList.add(o.getId());
        }

        int rows = updatePayStatus(idList.toArray(new String[idList.size()]), ProductOrderPayStatus.EXPIRED);
        if (rows > 0) {
            for (ProductOrderBean o : list) {
                ProductOrderFeeBean productOrderFeeBean = findFeeByOrderId(o.getOrderId());
                if (null != productOrderFeeBean) {
                    if (StringUtils.isNotBlank(productOrderFeeBean.getCouponRedId())) {
                        // 释放红包
                        couponRepertoryService.unlock(productOrderFeeBean.getCouponRedId());
                    }
                    if (StringUtils.isNotBlank(productOrderFeeBean.getCouponIncreaseId())) {
                        // 释放加息券
                        couponRepertoryService.unlock(productOrderFeeBean.getCouponIncreaseId());
                    }
                }

                // 账户余额解锁
                /*memberAccountService.orderExpireUnfreezeAmount(o.getOrderId());*/
                info("账户余额解锁 memberAccountService.orderExpireUnfreezeAmount : " + o.getOrderId());
            }
        }
        return rows;
    }

    @Override
    public BigDecimal calculateIncomeAmount(BigDecimal weight, Integer investDay, BigDecimal yearsIncome) {
        if (BigDecimalUtil.isZeroOrNull(weight) || null == investDay || BigDecimalUtil.isZeroOrNull(yearsIncome)) {
            return BigDecimal.ZERO;
        }
        // 收益计算公式 = 购买克重 * 投资期限 * 年化收益 / 100 / 365

        // *投资期限
        BigDecimal income = weight.multiply(new BigDecimal(investDay));
        // *年化收益/100/365
        income = income.multiply(yearsIncome);
        income = income.divide(new BigDecimal("100"), 10, ROUND_HALF_UP);
        income = income.divide(new BigDecimal("365"), 10, ROUND_HALF_UP);

        return BigDecimalUtil.to5Point(income);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RemoveCache(cleanAll = true)
    public void completeProductOrder(String id) {
        ProductOrderBean productOrderBean = findById(id);
        // 判断状态是否已处理 产品状态  1:未到期 2:已到期
        if (!ProductOrderStatus.NOT_EXPIRED.getValue().equals(productOrderBean.getStatus())) {
            Ensure.that(true).isTrue("17000703");
            return;
        }

        // 1、更新投资记录状态 =========================================================
        String[] ids = {id};
        int rows = updateStatus(ids, EXPIRED);
        Ensure.that(rows <= 0).isTrue("17000704");

        // 3、调整会员冻结资产总表 =====================================================
        memberGoldService.unfreezeAmount(productOrderBean.getMemberId(), productOrderBean.getAmount(), productOrderBean.getIncomeAmount(), BillGoldTradeType.TERM_TO_DEMAND, productOrderBean.getGoldPrice());

        // 4、触发消息提醒 ============================================================
        msgByComplete(productOrderBean.getMemberId(), productOrderBean.getProductName(), BigDecimalUtil.add(productOrderBean.getAmount(), productOrderBean.getIncomeAmount()),
                productOrderBean.getOrderId(), productOrderBean.getYearsIncome(), productOrderBean.getAmount(),
                productOrderBean.getEndTimeString());

        // 5、使用加息券 ============================================================
        ProductOrderFeeBean productOrderFeeBean = findFeeByOrderId(productOrderBean.getOrderId());
        if (null != productOrderFeeBean) {
            if (StringUtils.isNotBlank(productOrderFeeBean.getCouponIncreaseId())) {
                // 使用加息券
                donationCash(productOrderFeeBean.getCouponIncreaseId(),
                        productOrderFeeBean.getCouponIncreaseMoney(),
                        productOrderFeeBean.getCouponIncreaseAmount(), productOrderBean.getProductName());

                sendCouponIncrease(productOrderBean.getOrderId());
            }
        }
    }

    @Override
    @RemoveCache(cleanAll = true)
    public void completePay(String orderId) {
        info("orderId = [" + orderId + "]");
        // 1、获取分布式锁防止重复调用 =====================================================
        String key = "ProductOrderServiceImpl:completePay:" + orderId;
        if (!redisGlobalLock.lock(key)) {
            // 如果没有获取锁
            Ensure.that(true).isTrue("17000706");
        }
        try {
            info("支付完成。orderId = " + orderId);

            // 2、更改支付状态 ================================================================
            ProductOrderBean productOrderBean = findByOrderId(orderId);
            if (ProductOrderPayStatus.COMPLETE.getValue().equals(productOrderBean.getPayStatus())) {
                // 如果不是待支付状态
                info("订单无法重复支付。PayStatus = " + productOrderBean.getPayStatus());
                Ensure.that(true).isTrue("17000705");
            }

            String[] ids = {productOrderBean.getId()};
            int rows = updatePayStatus(ids, ProductOrderPayStatus.COMPLETE);
            info("更改订单支付状态 rows = " + rows);
            Ensure.that(rows).isLt(1, "00000005");

            // 3、如果购买的是活期金 ==========================================================
            // 产品类型 1:新手专享 2:活动产品  3:活期产品 4:定期产品
            if (productOrderBean.getType() == ProductTypeEnum.CURRENT.getType()) {
                rows = updateStatus(ids, EXPIRED);
                info("活期产品，更改订单状态 rows = " + rows);
                Ensure.that(rows).isLt(1, "00000005");
                // 3.1、调整会员资产账户信息【T日本金】 ==============================================
                memberGoldService.addPrincipalNowAmount(productOrderBean.getMemberId(), productOrderBean.getAmount(), BillGoldTradeType.BUY_DEMAND, productOrderBean.getGoldPrice());
            } else {
                // 3.2、调整会员资产账户信息【冻结资产】 ==============================================
                memberGoldService.freezeAmount(productOrderBean.getMemberId(), productOrderBean.getAmount(), productOrderBean.getIncomeAmount());

                ProductOrderFeeBean productOrderFeeBean = findFeeByOrderId(orderId);
                if (null != productOrderFeeBean) {
                    if (StringUtils.isNotBlank(productOrderFeeBean.getCouponRedId())) {
                        // 使用红包
                        /*SerializeObject o = couponRepertoryService.consumeCoupon(productOrderFeeBean.getCouponRedId(),
                                productOrderBean.getActualAmount(),
                                UF.toInt(productOrderBean.getInvestDay()),
                                productOrderBean.getOrderId());*/
                        SerializeObject o = couponRepertoryService.consumeCoupon(productOrderFeeBean.getCouponRedId(),
                                productOrderBean.getActualAmount(),
                                productOrderBean.getOrderId());
                        info(toJsonText(o));
                        info("使用红包成功：" + productOrderFeeBean.getCouponRedId());
                        // 发放红包
                        donationCash(productOrderFeeBean.getCouponRedId(),
                                productOrderFeeBean.getCouponRedAmount(),
                                null, productOrderBean.getProductName());
                        info("发放红包成功：" + productOrderFeeBean.getCouponRedId());
                        sendCouponRed(orderId);
                        info("更改发放状态成功：" + orderId);
                    }
                    if (StringUtils.isNotBlank(productOrderFeeBean.getCouponIncreaseId())) {
                        // 使用加息券
                        /*SerializeObject o = couponRepertoryService.consumeCoupon(productOrderFeeBean.getCouponIncreaseId(),
                                productOrderBean.getActualAmount(),
                                UF.toInt(productOrderBean.getInvestDay()),
                                productOrderBean.getOrderId());*/
                        SerializeObject o = couponRepertoryService.consumeCoupon(productOrderFeeBean.getCouponIncreaseId(),
                                productOrderBean.getActualAmount(),
                                productOrderBean.getOrderId());
                        info(toJsonText(o));
                        info("使用加息券成功：" + productOrderFeeBean.getCouponIncreaseId());
                    }
                }
            }

            // 3.2.1 触发消息
            msgByBuyGold(productOrderBean.getId());
            info("触发消息成功：" + productOrderBean.getId());

            // 投资返利（消息队列）
            rewardsByCompletePay(productOrderBean.getId());
            info("投资返利（消息队列）成功：" + productOrderBean.getId());
            SerializeObject<ProductFindBean> obj = productService.queryProductById(productOrderBean.getProductId());
            int isActivity = 2;
            if (null != obj && obj.getCode() == ResultType.NORMAL) {
                ProductFindBean productBean = obj.getData();
                if (productBean != null) {
                    isActivity = productBean.getIsActivity();
                }
            }
            // 生成e签宝合同
            esignAfterCompletePay(productOrderBean, isActivity);
        } catch (Exception e) {
            throw e;
        } finally {
            // 4、释放分布式锁 ================================================================
            redisGlobalLock.unlock(key);
        }
    }

    @Override
    public void sendCouponRed(String orderId) {
        sendCoupon(1, orderId);
    }

    @Override
    public void sendCouponIncrease(String orderId) {
        sendCoupon(2, orderId);
    }

    @Override
    @RemoveCache(cleanAll = true)
    @Transactional(rollbackFor = Exception.class)
    public void chooseCoupon(String memberId, String orderId, String couponRedId, String couponIncreaseId) {
        info("chooseCoupon memberId = [" + memberId + "], orderId = [" + orderId + "], couponRedId = [" + couponRedId + "], couponIncreaseId = [" + couponIncreaseId + "]");
        if (StringUtils.isBlank(memberId)) {
            Ensure.that(true).isTrue("00000102");
        }
        if (StringUtils.isBlank(memberId) || StringUtils.isBlank(orderId)) {
            Ensure.that(true).isTrue("00000002");
        }
        ProductOrderBean productOrderBean = findByOrderId(orderId);
        if (null == productOrderBean || StringUtils.isBlank(productOrderBean.getMemberId()) ||
                !memberId.equals(productOrderBean.getMemberId())) {
            Ensure.that(true).isTrue("17000716");
        }
        if (null == productOrderBean.getPayStatus() || !ProductOrderPayStatus.WAIT.getValue().equals(productOrderBean.getPayStatus())) {
            Ensure.that(true).isTrue("17000717");
        }

        String key = "ProductOrderServiceImpl:chooseCoupon:" + memberId;
        if (!redisGlobalLock.lock(key)) {
            Ensure.that(true).isTrue("17000714");
        }

        try {
            ProductOrderFeeBean productOrderFeeBean = findFeeByOrderId(orderId);
            if (null == productOrderFeeBean) {
                productOrderFeeBean = new ProductOrderFeeBean();
                productOrderFeeBean.setOrderId(orderId);
                productOrderFeeBean.setProductOrderId(productOrderBean.getId());
            } else {
                // 解锁红包、加息券
                if (StringUtils.isNotBlank(productOrderFeeBean.getCouponRedId())) {
                    SerializeObject obj = couponRepertoryService.unlock(productOrderFeeBean.getCouponRedId());
                    if (null == obj || ResultType.NORMAL != obj.getCode()) {
                        // 释放失败
                        error("解锁红包失败：" + productOrderFeeBean.getCouponRedId());
                        error(toJsonText(obj));
                        if (null == obj) {
                            Ensure.that(true).isTrue("00000005");
                        } else {
                            Ensure.that(true).isTrue(obj.getMsg());
                        }
                    }
                }
                if (StringUtils.isNotBlank(productOrderFeeBean.getCouponIncreaseId())) {
                    SerializeObject obj = couponRepertoryService.unlock(productOrderFeeBean.getCouponIncreaseId());
                    if (null == obj || ResultType.NORMAL != obj.getCode()) {
                        // 释放失败
                        error("解锁加息券失败：" + productOrderFeeBean.getCouponIncreaseId());
                        error(toJsonText(obj));
                        if (null == obj) {
                            Ensure.that(true).isTrue("00000005");
                        } else {
                            Ensure.that(true).isTrue(obj.getMsg());
                        }
                    }
                }
            }
            // 锁定红包、加息券
            if (StringUtils.isNotBlank(couponRedId)) {
                /*SerializeObject obj = couponRepertoryService.lock(couponRedId,
                        productOrderBean.getActualAmount(),
                        UF.toInt(productOrderBean.getInvestDay()));*/
                SerializeObject obj = couponRepertoryService.lock(couponRedId);
                if (null == obj || ResultType.NORMAL != obj.getCode()) {
                    // 释放失败
                    error("锁定红包失败：" + couponRedId);
                    error(toJsonText(obj));
                    if (null == obj) {
                        Ensure.that(true).isTrue("00000005");
                    } else {
                        Ensure.that(true).isTrue(obj.getMsg());
                    }
                }
            }
            if (StringUtils.isNotBlank(couponIncreaseId)) {
                /*SerializeObject obj = couponRepertoryService.lock(couponIncreaseId,
                        productOrderBean.getActualAmount(),
                        UF.toInt(productOrderBean.getInvestDay()));*/
                SerializeObject obj = couponRepertoryService.lock(couponIncreaseId);
                if (null == obj || ResultType.NORMAL != obj.getCode()) {
                    // 释放失败
                    error("锁定加息券失败：" + couponIncreaseId);
                    error(toJsonText(obj));
                    if (null == obj) {
                        Ensure.that(true).isTrue("00000005");
                    } else {
                        Ensure.that(true).isTrue(obj.getMsg());
                    }
                }
            }
            ProductOrderFee productOrderFee = dozerBeanMapper.map(productOrderFeeBean, ProductOrderFee.class);
            productOrderFee.setCouponRedId(couponRedId);
            productOrderFee.setCouponIncreaseId(couponIncreaseId);
            if (StringUtils.isBlank(productOrderFee.getCouponRedId())) {
                productOrderFee.setCouponRedAmount(null);
                productOrderFee.setCouponRedSendTime(null);
            } else {
                // 查找金额
                SerializeObject<CouponMemberBean> obj = couponRepertoryService.getMemberCoupon(productOrderFee.getCouponRedId());
                if (null == obj || ResultType.NORMAL != obj.getCode()) {
                    // 释放失败
                    error("读取红包失败：" + productOrderFee.getCouponRedId());
                    error(toJsonText(obj));
                    if (null == obj) {
                        Ensure.that(true).isTrue("00000005");
                    } else {
                        Ensure.that(true).isTrue(obj.getMsg());
                    }
                }
                CouponMemberBean couponMemberBean = obj.getData();
                productOrderFee.setCouponRedAmount(new BigDecimal(couponMemberBean.getDiscountAmount()));
            }

            if (StringUtils.isBlank(productOrderFee.getCouponIncreaseId())) {
                productOrderFee.setCouponIncreaseAmount(null);
                productOrderFee.setCouponIncreaseMoney(null);
                productOrderFee.setCouponIncreaseRate(null);
                productOrderFee.setCouponIncreaseSendTime(null);
            } else {
                // 查找加息率
                SerializeObject<CouponMemberBean> obj = couponRepertoryService.getMemberCoupon(productOrderFee.getCouponIncreaseId());
                if (null == obj || ResultType.NORMAL != obj.getCode()) {
                    // 释放失败
                    error("读取加息券失败：" + productOrderFee.getCouponIncreaseId());
                    error(toJsonText(obj));
                    if (null == obj) {
                        Ensure.that(true).isTrue("00000005");
                    } else {
                        Ensure.that(true).isTrue(obj.getMsg());
                    }
                }
                CouponMemberBean couponMemberBean = obj.getData();
                BigDecimal couponIncreaseRate = new BigDecimal(couponMemberBean.getDiscountAmount());

                // 计算加息克重、加息金额
                BigDecimal couponIncreaseAmount = calculateIncomeAmount(productOrderBean.getAmount(), UF.toInt(productOrderBean.getInvestDay()), couponIncreaseRate);
                BigDecimal couponIncreaseMoney = BigDecimalUtil.to2Point(BigDecimalUtil.multiply(couponIncreaseAmount, productOrderBean.getGoldPrice()));

                productOrderFee.setCouponIncreaseAmount(couponIncreaseAmount);
                productOrderFee.setCouponIncreaseMoney(couponIncreaseMoney);
                productOrderFee.setCouponIncreaseRate(couponIncreaseRate);
                // 总年化收益率%
                productOrderFee.setTotalRateOfIncome(BigDecimalUtil.add(productOrderBean.getYearsIncome(), couponIncreaseRate));
            }

            if (StringUtils.isBlank(productOrderFee.getId())) {
                productOrderFee.setId(UF.getRandomUUID());
                productOrderFeeMapper.insert(productOrderFee);
            } else {
                productOrderFeeMapper.update(productOrderFee);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            // 释放分布式锁
            redisGlobalLock.unlock(key);
        }
    }

    @Override
    public BigDecimal sumOfAmount(String productId) {
        return productOrderMapper.sumOfAmount(productId);
    }


    @Override
    @SaveCache(cacheType = SEARCH)
    public DataTable<ProductOrderRecordBean> queryRecordByProductId(int pageNum, int pageSize, String productId) {
        Page<ProductOrderSummaryBean> page = PageHelper.startPage(pageNum, pageSize);
        List<ProductOrderRecordBean> dataList = new ArrayList<>();
        SerializeObject<ProductFindBean> obj = productService.queryProductById(productId);
        if (null != obj && obj.getCode() == ResultType.NORMAL) {
            ProductFindBean productBean = obj.getData();
            if (productBean != null && (productBean.getType() == ProductTypeEnum.ENTITY.getType() ||
                    productBean.getType() == ProductTypeEnum.SMOOTH_GOLD.getType()) ||
                    productBean.getType() == ProductTypeEnum.DISCOUNT_GOLD.getType()) {
                //实物金
                List<TbillBean> tbillBeans = payTbillMapper.queryBuyRecords(productId);
                if (!CollectionUtils.isEmpty(tbillBeans)) {
                    for (TbillBean tbillBean : tbillBeans) {
                        ProductOrderRecordBean productOrderRecordBean = new ProductOrderRecordBean();
                        productOrderRecordBean.setActualAmount(tbillBean.getPayAmount());
                        productOrderRecordBean.setFee(tbillBean.getFee());
                        productOrderRecordBean.setGoldPrice(tbillBean.getGoldPrice());
                        // 隐藏手机号码， 格式化日期
                        productOrderRecordBean.setMemberMobile(UF.getFormatMobile(tbillBean.getMobile()));
                        productOrderRecordBean.setMemberName(tbillBean.getMemberName());
                        productOrderRecordBean.setOrderId(tbillBean.getOrderNo());
                        productOrderRecordBean.setAmount(new BigDecimal(tbillBean.getTotalGram()));
                        productOrderRecordBean.setAddTimeString(tbillBean.getAddTime());
                        productOrderRecordBean.setProductId(productId);
                        dataList.add(productOrderRecordBean);
                    }
                }
            } else if (productBean != null && productBean.getType() == ProductTypeEnum.EXPERIENCE_GOLD.getType()) {
                //体验金
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("productId", productId);
                List<PayExperienceOrder> resultList = payExperienceOrderMapper.queryBuyRecordList(params);
                if (!CollectionUtils.isEmpty(resultList)) {
                    for (PayExperienceOrder payExperienceOrder : resultList) {
                        ProductOrderRecordBean productOrderRecordBean = new ProductOrderRecordBean();
                        productOrderRecordBean.setActualAmount(new BigDecimal(0));
                        productOrderRecordBean.setFee(new BigDecimal(0));
                        productOrderRecordBean.setGoldPrice(payExperienceOrder.getGoldPrice());
                        // 隐藏手机号码， 格式化日期
                        productOrderRecordBean.setMemberMobile(UF.getFormatMobile(payExperienceOrder.getMobile()));
                        productOrderRecordBean.setMemberName(payExperienceOrder.getName());
                        productOrderRecordBean.setOrderId(payExperienceOrder.getOrderNO());
                        productOrderRecordBean.setAmount(new BigDecimal(payExperienceOrder.getTotalGram()));
                        productOrderRecordBean.setAddTimeString(payExperienceOrder.getAddTime());
                        productOrderRecordBean.setProductId(productId);
                        dataList.add(productOrderRecordBean);
                    }
                }
            } else {
                // 全部支付状态
                Integer payStatus = ProductOrderPayStatus.COMPLETE.getValue();
                List<ProductOrderBean> list = query(null, null, null, null, null, null, payStatus, null, null, null,
                        null, null, null, null, null, null, null, productId, null, null);

                for (ProductOrderBean o : list) {
                    ProductOrderRecordBean productOrderRecordBean = dozerBeanMapper.map(o, ProductOrderRecordBean.class);
                    // 隐藏手机号码， 格式化日期
                    productOrderRecordBean.setMemberMobile(UF.getFormatMobile(o.getMemberMobile()));
                    dataList.add(productOrderRecordBean);
                }
            }
        }

        return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), dataList);
    }


    @Override
    public DataTable<ProductOrderBean> queryInfoByMemberId(int pageNum, int pageSize, String addTimeMinString, String addTimeMaxString,
                                                           String endTimeMinString, String endTimeMaxString, String memberId) {
        PageHelper.startPage(pageNum, pageSize);
        HashMap reqMap = new HashMap();
        reqMap.put("addTimeMinString", addTimeMinString);
        reqMap.put("addTimeMaxString", addTimeMaxString);
        reqMap.put("endTimeMinString", endTimeMinString);
        reqMap.put("endTimeMaxString", endTimeMaxString);
        reqMap.put("memberId", memberId);

        List<ProductOrder> productOrderList = productOrderMapper.queryInfoByMemberId(reqMap);
        PageInfo<ProductOrder> pageInfo = new PageInfo<>(productOrderList);
        List<ProductOrderBean> resultDataList = new ArrayList<>();
        for (ProductOrder o : pageInfo.getList()) {
            ProductOrderBean objBean = dozerBeanMapper.map(o, ProductOrderBean.class);
            objBean.setStartTimeString(UF.getFormatDateTime(o.getStartTime()));
            objBean.setEndTimeString(UF.getFormatDateTime(o.getEndTime()));
            objBean.setStopPayTimeString(UF.getFormatDateTime(o.getStopPayTime()));
            objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
            objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
            objBean.setProductOrderFeeBean(findFeeByOrderId(o.getOrderId()));
            resultDataList.add(objBean);
        }
        return new DataTable<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), resultDataList);
    }


    /**
     * 统计数量
     *
     * @param memberId  会员ID
     * @param type      产品类型 1:新手专享 2:活动产品  3:活期产品 4:定期产品
     * @param payStatus 支付状态  1:待支付 2:已支付 3:已过期
     * @param status    状态  1:未到期 2:已到期
     * @return
     */
    private Long countQuery(String memberId, Integer type, Integer payStatus, Integer status) {
        Page<ProductOrderBean> page = PageHelper.startPage(1, 1);
        List<ProductOrderBean> list = query(null, null, null, type, null, null, payStatus, status, null, null,
                null, null, null, null, memberId, null, null, null, null, null);

        return page.getTotal();
    }

    /**
     * 统计今日购买克重
     *
     * @param memberId 会员ID
     * @return
     */
    private BigDecimal countTodayBuyAmountQuery(String memberId) {
        String currentDate = UF.getFormatDate(UF.getDateTime());
        List<ProductOrderBean> list = query(null, null, null, null, null, null, null, null, null, null,
                null, null, UF.getDateTime(currentDate + " 00:00:00"), UF.getDateTime(currentDate + " 23:59:59"),
                memberId, null, null, null, null, null);

        // 包含活期、定期（金柚宝转入除外）
        BigDecimal todayBuyAmount = BigDecimal.ZERO;
        for (ProductOrderBean o : list) {
            if (PayType.TURN_INTO.getValue().equals(o.getPayType())) {
                // 如果是金柚宝转入
                continue;
            }
            if (ProductOrderPayStatus.EXPIRED.getValue().equals(o.getPayStatus())) {
                // 如果已过期
                continue;
            }

            // 购买克重累加
            todayBuyAmount = BigDecimalUtil.add(todayBuyAmount, o.getAmount());
        }

        return todayBuyAmount;
    }

    /**
     * 使用红包/加息券
     *
     * @param couponId     优惠券id
     * @param couponAmount 发放金额（红包金额或加息券折算金额）
     * @param goldAmount   加息券折算克重
     */
    private void donationCash(String couponId, BigDecimal couponAmount, BigDecimal goldAmount, String productName) {
        info("donationCash couponId = [" + couponId + "], couponAmount = [" + couponAmount + "], goldAmount = [" + goldAmount + "]");
        DonationCashMQ donationCashMQ = new DonationCashMQ();
        donationCashMQ.setCouponId(couponId);
        donationCashMQ.setCouponAmount(couponAmount);
        donationCashMQ.setGoldAmount(goldAmount);
        donationCashMQ.setProductName(productName);

        amqpTemplate.convertAndSend(QUEUE_COUPON_DONATION_CASH, donationCashMQ);
    }

    /**
     * 支付完成后发放奖励（投资返利）
     *
     * @param id 投资记录ID
     */
    private void rewardsByCompletePay(String id) {
        ProductOrderBean o = findById(id);
        // 投资次数
        int investTimes = countQuery(
                o.getMemberId(),
                ProductTypeEnum.REGULAR.getType(),
                ProductOrderPayStatus.COMPLETE.getValue(),
                null).intValue();
        if (o.getPayType() == 1) {
            RewardsMQ rewardsMQ = new RewardsMQ();
            rewardsMQ.setProductId(o.getProductId());
            rewardsMQ.setInvestTimes(investTimes);
            rewardsMQ.setScene(2);
            rewardsMQ.setMemberId(o.getMemberId());
            rewardsMQ.setOrderId(id);
            rewardsMQ.setAmount(o.getAmount());
            rewardsMQ.setPayTotalAmount(o.getItemAmount());

            amqpTemplate.convertAndSend(QUEUE_ACTIVITY_REWARDS, rewardsMQ);
        }
    }

    /**
     * 支付完成后生成签章
     */
    public void esignAfterCompletePay(Object object, int isActivity) {
        ContractMQ contractMQ = null;
        if (object instanceof ProductOrder) {
            ProductOrder entity = (ProductOrder) object;
            contractMQ = new ContractMQ();
            contractMQ.setInvestDay(Integer.parseInt(entity.getInvestDay()));
            contractMQ.setMemberId(entity.getMemberId());
            contractMQ.setOrderNO(entity.getOrderId());
            contractMQ.setPrice(entity.getGoldPrice());
            contractMQ.setProductType(entity.getType());
            contractMQ.setProductId(entity.getProductId());
            contractMQ.setProductName(entity.getProductName());
            contractMQ.setTradeAmount(entity.getActualAmount());
            contractMQ.setIsActivity(isActivity);
            contractMQ.setTradeDate(UF.getFormatDate(UF.getDateTime()));
            contractMQ.setWeight(entity.getAmount());
        } else if (object instanceof ProductOrderBean) {
            ProductOrderBean entity = (ProductOrderBean) object;
            contractMQ = new ContractMQ();
            contractMQ.setInvestDay(Integer.parseInt(entity.getInvestDay()));
            contractMQ.setMemberId(entity.getMemberId());
            contractMQ.setOrderNO(entity.getOrderId());
            contractMQ.setPrice(entity.getGoldPrice());
            contractMQ.setProductType(entity.getType());
            contractMQ.setProductId(entity.getProductId());
            contractMQ.setIsActivity(isActivity);
            contractMQ.setProductName(entity.getProductName());
            contractMQ.setTradeAmount(entity.getActualAmount());
            contractMQ.setTradeDate(UF.getFormatDate(UF.getDateTime()));
            contractMQ.setWeight(entity.getAmount());
        }
        if (contractMQ != null) {
            info("e签宝合同消息：" + JSONObject.toJSONString(contractMQ));
            amqpTemplate.convertAndSend(QUEUE_ESIGN_CONTRACT, contractMQ);
        }
    }

    /**
     * 购买黄金消息提醒
     *
     * @param id 购买记录ID
     */
    private void msgByBuyGold(String id) {
        info("msgByBuyGold id = [" + id + "]");
        ProductOrderBean o = findById(id);

        Msg msg = new Msg();
        msg.setMemberId(o.getMemberId());

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("productName", o.getProductName());
        paramMap.put("changeGram", BigDecimalUtil.to5Point(o.getAmount()).toString());
        if (ProductTypeEnum.CURRENT.getType() == o.getType()) {
            // 活期
            msg.setType(CommonConstants.MsgType.BUY_CURRENT_GOLD.getIndex());
            MemberGoldBean memberGoldBean = memberGoldService.findByMemberId(o.getMemberId());
            // 可用资产
            paramMap.put("gram", BigDecimalUtil.to5Point(memberGoldBean.getUsableAmount()).toString());
        } else {
            // 定期
            msg.setType(CommonConstants.MsgType.BUY_GOLD.getIndex());
            paramMap.put("investDay", o.getInvestDay());
        }
        msg.setParamMap(paramMap);

        amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
    }

    /**
     * 待支付消息提醒
     *
     * @param memberId 会员ID
     */
    private void msgByWaitPay(String memberId) {
        info("msgByWaitPay");
        Msg msg = new Msg();
        msg.setMemberId(memberId);
        msg.setType(CommonConstants.MsgType.WAIT_PAY_ORDER.getIndex());
        SerializeObject resultRate = rateSettingsService.get(RateKeyEnum.UNPAID_TIME.getKey());
        if (resultRate.getData() != null) {
            Map<String, Object> resultRateMap = (Map<String, Object>) resultRate.getData();
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("unpaidTime", String.valueOf(resultRateMap.get(RateKeyEnum.UNPAID_TIME.getKey())));
            msg.setParamMap(paramMap);
        }
        amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
    }

    /**
     * 产品到期消息提醒
     *
     * @param memberId    会员ID
     * @param productName 产品名称
     * @param addGram     增加克重
     */
    private void msgByComplete(String memberId, String productName, BigDecimal addGram, String orderId, BigDecimal yearsIncome, BigDecimal amount, String endTime) {
        info("msgByComplete memberId = [" + memberId + "], productName = [" + productName + "], addGram = [" + addGram + "]");
        MemberGoldBean memberGoldBean = memberGoldService.findByMemberId(memberId);
        // 可用资产
        BigDecimal usableAmount = memberGoldBean.getUsableAmount();

        Msg msg = new Msg();
        msg.setMemberId(memberId);
        msg.setType(CommonConstants.MsgType.BUY_GOLD_EXPIRE.getIndex());

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("productName", productName);
        paramMap.put("addGram", BigDecimalUtil.to5Point(addGram).toString());
        paramMap.put("gram", BigDecimalUtil.to5Point(usableAmount).toString());
        msg.setParamMap(paramMap);

        // 凌晨一点触发任务，延后八个小时发送短信
        amqpTemplate.convertAndSend(QUEUE_DELAY_PER_MESSAGE_TTL_MSG_SEND, msg, new DelayMessagePostProcessor(8 * 60 * 60 * 1000));

        /**
         * 微信服务号消息推送  定期产品到期后 延后八个小时发送短信
         */
        WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
        wxMessageParamBean.setMemberId(memberId);
        //消息推送类型
        wxMessageParamBean.setType(WxTemplateEnum.PRODUCT_EXPIRE.getType());
        WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.PRODUCT_EXPIRE.getType());
        WxNotifyData wxNotifyData = new WxNotifyData();

        Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
        WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
        first.setDataValue(wxTemplateEnum.getFirstData().replace("{product}", productName).
                replace("{weight}", addGram.toString()).replace("{balance}", BigDecimalUtil.to5Point(usableAmount).toString()));
        wxParamMap.put("first", first);

        WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
        keyword1.setDataValue(memberGoldBean.getMemberMobile());
        wxParamMap.put("keyword1", keyword1);

        WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
        keyword2.setDataValue(BigDecimalUtil.to5Point(addGram).toString() + "克");
        wxParamMap.put("keyword2", keyword2);

        WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
        keyword3.setDataValue(orderId);
        wxParamMap.put("keyword3", keyword3);

        WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
        keyword4.setDataValue(BigDecimalUtil.to2Point(yearsIncome).toString());
        wxParamMap.put("keyword4", keyword4);

        WxNotifyData.TemplateDataAttr keyword5 = new WxNotifyData.TemplateDataAttr();
        keyword5.setDataValue(endTime);
        wxParamMap.put("keyword5", keyword5);

        WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
        remark.setDataValue(wxTemplateEnum.getRemark());
        wxParamMap.put("remark", remark);

        wxNotifyData.setData(wxParamMap);
        wxMessageParamBean.setTemplateData(wxNotifyData);
        amqpTemplate.convertAndSend(QUEUE_DELAY_PER_MESSAGE_TTL_MSG_WX_SEND, wxMessageParamBean, new DelayMessagePostProcessor(8 * 60 * 60 * 1000));

    }

    /**
     * 活期转定期（金柚宝转入）
     *
     * @param memberId    会员ID
     * @param productName 产品名称
     * @param changeGram  交易数量
     * @param investDay   期限
     * @param reduceGram  可用量减少
     */
    private void msgByTurnInto(String memberId, String productName, BigDecimal changeGram, String investDay, BigDecimal reduceGram) {
        info("msgByTurnInto memberId = [" + memberId + "], productName = [" + productName + "], changeGram = [" + changeGram + "], investDay = [" + investDay + "], reduceGram = [" + reduceGram + "]");
        MemberGoldBean memberGoldBean = memberGoldService.findByMemberId(memberId);
        // 可用资产
        BigDecimal usableAmount = memberGoldBean.getUsableAmount();

        Msg msg = new Msg();
        msg.setMemberId(memberId);
        msg.setType(CommonConstants.MsgType.CURRENT_TO_PERIOD.getIndex());

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("productName", productName);
        paramMap.put("changeGram", BigDecimalUtil.to5Point(changeGram).toString());
        paramMap.put("investDay", investDay);
        paramMap.put("reduceGram", BigDecimalUtil.to5Point(reduceGram).toString());
        paramMap.put("gram", BigDecimalUtil.to5Point(usableAmount).toString());
        msg.setParamMap(paramMap);

        amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
    }

    /**
     * 获取数据列表
     *
     * @param order           排序字段
     * @param sort            排序方式 desc或asc
     * @param orderId         订单号
     * @param type            产品类型 1:新手专享 2:活动产品  3:活期产品 4:定期产品
     * @param typeList        产品类型集合
     * @param payType         支付类型 1:现金购买 2:金柚宝转入
     * @param payStatus       支付状态  1:待支付 2:已支付 3:已过期
     * @param status          产品状态  1:未到期 2:已到期
     * @param overStopPayTime 是否查询过期订单
     * @param overEndTime     是否收益到期订单
     * @param amountMin       最小购买克重
     * @param amountMax       最大购买克重
     * @param addTimeMin      最小投资时间
     * @param addTimeMax      最大投资时间
     * @param memberId        会员ID
     * @param memberName      会员名称
     * @param memberMobile    会员手机
     * @param productId       产品ID
     * @param keyword         关键字
     * @return 列表
     */
    private List<ProductOrderBean> query(String order, String sort, String orderId, Integer type, List<Integer> typeList,
                                         Integer payType, Integer payStatus, Integer status, Boolean overStopPayTime, Boolean overEndTime,
                                         BigDecimal amountMin, BigDecimal amountMax, LocalDateTime addTimeMin, LocalDateTime addTimeMax,
                                         String memberId, String memberName, String memberMobile, String productId, String keyword, String channelId) {
        if (null != addTimeMax) {
            // 加一天减一秒
            addTimeMax = addTimeMax.plusDays(1).minusSeconds(1);
        }
        List<ProductOrderBean> dataList = new ArrayList<>();
        List<ProductOrder> list = productOrderMapper.query(
                getParams(keyword, order, sort)
                        .put("orderId", orderId)
                        .put("type", type)
                        .put("typeList", typeList)
                        .put("payType", payType)
                        .put("payStatus", payStatus)
                        .put("channelId", channelId)
                        .put("status", status)
                        .put("overStopPayTime", overStopPayTime)
                        .put("overEndTime", overEndTime)
                        .put("amountMin", amountMin)
                        .put("amountMax", amountMax)
                        .put("addTimeMin", addTimeMin)
                        .put("addTimeMax", addTimeMax)
                        .put("memberId", memberId)
                        .put("memberName", UF.escapeSql(memberName))
                        .put("memberMobile", UF.escapeSql(memberMobile))
                        .put("productId", productId)
                        .toMap());
        for (ProductOrder o : list) {
            ProductOrderBean objBean = dozerBeanMapper.map(o, ProductOrderBean.class);

            objBean.setStartTimeString(UF.getFormatDateTime(o.getStartTime()));
            objBean.setEndTimeString(UF.getFormatDateTime(o.getEndTime()));
            objBean.setStopPayTimeString(UF.getFormatDateTime(o.getStopPayTime()));
            objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
            objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
            objBean.setProductOrderFeeBean(findFeeByOrderId(o.getOrderId()));

            dataList.add(objBean);
        }
        return dataList;
    }

    /**
     * 发放红包或优惠券
     *
     * @param type    1：红包 2：优惠券
     * @param orderId 订单流水号
     * @return 操作影响的记录数
     */
    private int sendCoupon(int type, String orderId) {
        ProductOrderFeeBean productOrderFeeBean = findFeeByOrderId(orderId);
        if (null == productOrderFeeBean) {
            return 0;
        }
        String[] id = {productOrderFeeBean.getId()};
        if (type == 1) {
            return productOrderFeeMapper.updateByPrimaryKeySelective(
                    getParams()
                            .put("id", id)
                            .put("couponRedSendTime", UF.getDateTime())
                            .toMap()
            );
        } else {
            return productOrderFeeMapper.updateByPrimaryKeySelective(
                    getParams()
                            .put("id", id)
                            .put("couponIncreaseSendTime", UF.getDateTime())
                            .toMap()
            );
        }
    }

    /**
     * 根据流水号获取订单红包等费用信息
     *
     * @param orderId 订单流水号
     * @return 费用信息
     */
    private ProductOrderFeeBean findFeeByOrderId(String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return null;
        }
        List<ProductOrderFee> list = productOrderFeeMapper.query(
                getParams(null, null, null)
                        .put("orderId", orderId)
                        .toMap());
        if (null == list || list.isEmpty()) {
            return null;
        }

        ProductOrderFee o = list.get(0);
        ProductOrderFeeBean productOrderFeeBean = dozerBeanMapper.map(o, ProductOrderFeeBean.class);
        // 红包发放时间
        if (StringUtils.isNotBlank(o.getCouponRedId())) {
            if (null != o.getCouponRedSendTime()) {
                productOrderFeeBean.setCouponRedSendTimeString(UF.getFormatDateTime(o.getCouponRedSendTime()));
            }
        }
        // 加息券发放时间
        if (StringUtils.isNotBlank(o.getCouponIncreaseId())) {
            if (null != o.getCouponIncreaseSendTime()) {
                productOrderFeeBean.setCouponIncreaseSendTimeString(UF.getFormatDateTime(o.getCouponIncreaseSendTime()));
            }
        }

        return productOrderFeeBean;
    }

    public void wxSend(String memberId, String productName, String orderId, BigDecimal goldPrice, BigDecimal payAmount, BigDecimal amount, ProductOrder entity) {
        WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
        wxMessageParamBean.setMemberId(memberId);
        wxMessageParamBean.setType(WxTemplateEnum.PURCHASE_TIMING_PRODUCT_SUCCEED.getType());
        WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.PURCHASE_TIMING_PRODUCT_SUCCEED.getType());
        Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
        WxNotifyData wxNotifyData = new WxNotifyData();
        WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
        first.setDataValue(wxTemplateEnum.getFirstData().replace("{product}", entity.getProductName()).
                replace("{deadline}", entity.getInvestDay()).replace("{expireTime}", UF.getFormatDate(entity.getEndTime())).
                replace("{predictEarnings}", BigDecimalUtil.to5Point(entity.getIncomeAmount()).toString()));
        wxParamMap.put("first", first);

        WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
        keyword1.setDataValue(orderId);
        wxParamMap.put("keyword1", keyword1);

        WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
        keyword2.setDataValue(BigDecimalUtil.to5Point(amount).toString());
        wxParamMap.put("keyword2", keyword2);

        WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
        keyword3.setDataValue(BigDecimalUtil.to2Point(payAmount).toString());
        wxParamMap.put("keyword3", keyword3);

        WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
        keyword4.setDataValue(BigDecimalUtil.to2Point(goldPrice).toString());
        wxParamMap.put("keyword4", keyword4);

        WxNotifyData.TemplateDataAttr keyword5 = new WxNotifyData.TemplateDataAttr();
        keyword5.setDataValue(DateUtils.dateToStr(new Date(), DateUtils.patter));
        wxParamMap.put("keyword5", keyword5);

        WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
        remark.setDataValue(wxTemplateEnum.getRemark());
        wxParamMap.put("remark", remark);

        wxNotifyData.setData(wxParamMap);
        wxMessageParamBean.setTemplateData(wxNotifyData);
        amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
    }

}

